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) } }
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 }
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()) } }
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 }