Ejemplo n.º 1
0
func TestDecomposeBytes(t *testing.T) {
	ass := assert.New(t)

	// buffer is smaller than header
	{
		id := "0"
		name := "test"

		h := dingo.NewHeader(id, name)
		h.Append(100000)

		bs, err := dingo.DecomposeBytes(h, make([]byte, 5))
		ass.Nil(bs)
		ass.NotNil(err)
	}

	// buffer is smaller than registry
	{
		id := "0"
		name := "test"

		h := dingo.NewHeader(id, name)
		h.Append(100000)
		b, err := h.Flush(0)
		ass.Nil(err)

		h, err = dingo.DecodeHeader(b)
		ass.Nil(err)
		bs, err := dingo.DecomposeBytes(h, b)
		ass.Len(bs, 0)
		ass.NotNil(err)
	}
}
Ejemplo n.º 2
0
func (me *broker) _consumer_routine_(
	quit <-chan int,
	wait *sync.WaitGroup,
	events chan<- *dingo.Event,
	tasks chan<- []byte,
	receipts <-chan *dingo.TaskReceipt,
	name string,
) {
	defer wait.Done()

	conn := me.pool.Get()
	defer conn.Close()

	qn := fmt.Sprintf("%v.%v", _redisTaskQueue, name)

	for {
		select {
		case _, _ = <-quit:
			goto clean
		default:
			// blocking call on redis server
			reply, err := conn.Do("BRPOP", qn, me.cfg.GetListenTimeout())
			if err != nil {
				events <- dingo.NewEventFromError(dingo.ObjT.Consumer|dingo.ObjT.NamedConsumer, err)
				break
			}

			if reply == nil {
				// timeout, go for next round
				break
			}

			// the return value from BRPOP should be
			// an slice with length 2
			v, ok := reply.([]interface{})
			if !ok {
				events <- dingo.NewEventFromError(
					dingo.ObjT.Consumer|dingo.ObjT.NamedConsumer,
					errors.New(fmt.Sprintf("invalid reply: %v", reply)),
				)
				break
			}
			if len(v) != 2 {
				events <- dingo.NewEventFromError(
					dingo.ObjT.Consumer|dingo.ObjT.NamedConsumer,
					errors.New(fmt.Sprintf("invalid reply: %v", reply)),
				)
				break
			}

			b, ok := v[1].([]byte)
			if !ok {
				events <- dingo.NewEventFromError(
					dingo.ObjT.Consumer|dingo.ObjT.NamedConsumer,
					errors.New(fmt.Sprintf("invalid reply: %v", reply)),
				)
				break
			}

			h, err := dingo.DecodeHeader(b)
			if err != nil {
				events <- dingo.NewEventFromError(dingo.ObjT.Consumer|dingo.ObjT.NamedConsumer, err)
				break
			}

			tasks <- b
			rcpt, ok := <-receipts
			if !ok {
				goto clean
			}

			if rcpt.ID != h.ID() {
				events <- dingo.NewEventFromError(
					dingo.ObjT.Consumer|dingo.ObjT.NamedConsumer,
					errors.New(fmt.Sprintf("expected: %v, received: %v", h, rcpt)),
				)
				break
			}
		}
	}
clean:
	return
}
Ejemplo n.º 3
0
func TestHeader(t *testing.T) {
	ass := assert.New(t)

	// basic case
	{
		id := "041ebfa0-9b6e-11e5-ae12-0002a5d5c51b"
		name := "test"

		b, err := dingo.NewHeader(id, name).Flush(0)
		ass.Nil(err)

		h, err := dingo.DecodeHeader(b)
		ass.Nil(err)
		ass.Equal(name, h.Name())
		ass.Equal(id, h.ID())
	}

	// zero length name, should be ok
	{
		id := "4c257820-9b6e-11e5-b7d5-0002a5d5c51b"
		name := ""

		b, err := dingo.NewHeader(id, name).Flush(0)
		ass.Nil(err)

		h, err := dingo.DecodeHeader(b)
		ass.Nil(err)
		ass.Equal(name, h.Name())
		ass.Equal(id, h.ID())
	}

	// wrong version
	{
		id := "7dd224e0-9b6e-11e5-aa62-0002a5d5c51b"
		name := ""

		b, err := dingo.NewHeader(id, name).Flush(0)
		ass.Nil(err)

		b[0] ^= 0xff
		h, err := dingo.DecodeHeader(b)
		ass.NotNil(err)
		ass.Nil(h)
	}

	// length is not enough
	{
		id := "7dd224e0-9b6e-11e5-aa62-0002a5d5c51b"
		name := ""

		b, err := dingo.NewHeader(id, name).Flush(0)
		ass.Nil(err)

		h, err := dingo.DecodeHeader(b[:17])
		ass.NotNil(err)
		ass.Nil(h)
	}

	// payloads
	{
		id := "7dd224e0-9b6e-11e5-aa62-0002a5d5c51b"
		name := "test"

		h := dingo.NewHeader(id, name)

		// append several dummy payloads
		for i := 0; i < 1000; i++ {
			h.Append(10)
		}

		b, err := h.Flush(0)
		ass.Nil(err)

		h, err = dingo.DecodeHeader(b)
		ass.Nil(err)
		ass.NotNil(h)
		ass.Len(h.Registry(), 1000)
		for _, v := range h.Registry() {
			ass.Equal(uint64(10), v)
		}

		// reset
		h.Reset()
		b, err = h.Flush(0)
		ass.Nil(err)

		h, err = dingo.DecodeHeader(b)
		ass.Nil(err)
		ass.NotNil(h)
		ass.Len(h.Registry(), 0)

		// flush with reset
		for i := 0; i < 1000; i++ {
			h.Append(10)
		}
		ass.Len(h.Registry(), 1000)
		_, err = h.Flush(0)
		ass.Nil(err)
		ass.Len(h.Registry(), 0)
	}

	// short id
	{
		id := "0"
		name := "test"

		b, err := dingo.NewHeader(id, name).Flush(0)
		ass.Nil(err)

		h, err := dingo.DecodeHeader(b)
		ass.Nil(err)
		ass.Equal(name, h.Name())
		ass.Equal(id, h.ID())
	}
}
Ejemplo n.º 4
0
func (me *broker) _consumer_routine_(
	quit <-chan int,
	wait *sync.WaitGroup,
	events chan<- *dingo.Event,
	tasks chan<- []byte,
	receipts <-chan *dingo.TaskReceipt,
	ci *AmqpChannel,
	queueName string,
) {
	defer wait.Done()
	defer me.receiver.ReleaseChannel(ci)

	// acquire an tag
	id := <-me.consumerTags
	tag := fmt.Sprintf("dingo.consumer.%d", id)

	// return id
	defer func(id int) {
		me.consumerTags <- id
	}(id)

	dv, err := ci.Channel.Consume(
		queueName,
		tag,   // consumer Tag
		false, // autoAck
		false, // exclusive
		false, // noLocal
		false, // noWait
		nil,   // args
	)
	if err != nil {
		events <- dingo.NewEventFromError(dingo.ObjT.Consumer|dingo.ObjT.NamedConsumer, err)
		return
	}

	for {
		select {
		case d, ok := <-dv:
			if !ok {
				goto clean
			}

			ok = func() (ok bool) {
				var (
					reply *dingo.TaskReceipt
					err   error
				)
				defer func() {
					if err != nil || !ok {
						d.Nack(false, false)
						events <- dingo.NewEventFromError(dingo.ObjT.Consumer|dingo.ObjT.NamedConsumer, err)
					} else {
						d.Ack(false)
					}
				}()
				h, err := dingo.DecodeHeader(d.Body)
				if err != nil {
					return
				}
				tasks <- d.Body
				// block here for receipts
				reply, ok = <-receipts
				if !ok {
					return
				}

				if reply.ID != h.ID() {
					err = errors.New(fmt.Sprintf("expected: %v, received: %v", h, reply))
					return
				}
				if reply.Status == dingo.ReceiptStatus.WorkerNotFound {
					err = errors.New(fmt.Sprintf("worker not found: %v", h))
					return
				}
				return
			}()
			if !ok {
				goto clean
			}
		case _, _ = <-quit:
			goto clean
		}
	}

clean:
	err_ := ci.Channel.Cancel(tag, false)
	if err_ != nil {
		events <- dingo.NewEventFromError(dingo.ObjT.Consumer|dingo.ObjT.NamedConsumer, err_)
		// should we return here?,
		// we still need to clean the delivery channel...
	}

	// conuming remaining deliveries,
	// and don't ack them. (make them requeue in amqp)
	for cleared := false; cleared == false; {
		select {
		case d, ok := <-dv:
			if !ok {
				cleared = true
				break
			}
			// requeue
			d.Nack(false, true)
		default:
			cleared = true
		}
	}

	// close output channel
	close(tasks)

	return
}