func (d *Driver) Enqueue(queue string, id uid.ID, e *storage.Envelope, opts *storage.EnqueueOptions) (*storage.EnqueueMeta, error) { var meta storage.EnqueueMeta msgs := d.queues.get(queue) now := time.Now().UnixNano() d.m.Lock() defer d.m.Unlock() if opts.AccumTime > 0 { for _, msg := range *msgs { if msg.availAt > now && msg.accumlating { meta.AccumState = storage.AccumAdded msg.envelope.AddMessage(e.Messages[0]) return &meta, nil } } } msg := &message{ availAt: now, envelope: e, } if opts.AccumTime > 0 { msg.availAt += int64(opts.AccumTime) msg.accumlating = true meta.AccumState = storage.AccumStarted } heap.Push(msgs, msg) if opts.AccumTime == 0 { event.Emit(event.EventMessageAvailable, queue) } return &meta, nil }
func (d *Driver) Dequeue(queue string, eid uid.ID) (e *storage.Envelope, err error) { now := time.Now().UnixNano() d.m.Lock() defer d.m.Unlock() msgs := d.queues.get(queue) for i, n := 0, len(*msgs); i < n; i++ { msg := (*msgs)[i] if msg.availAt > now { break } if !msg.envelope.Retry.IsValid() { event.Emit(event.EventMessageDiscarded, msg.envelope) msg.removed = true } if msg.removed { heap.Remove(msgs, i) i-- n-- continue } e = msg.envelope msg.eid = eid msg.availAt = now + int64(msg.envelope.Timeout) msg.envelope.Retry.Decr() msg.accumlating = false heap.Fix(msgs, i) d.ephemeralIndex[eid] = msg return } err = storage.ErrEmpty return }
func (d *Driver) Dequeue(queue string, eid uid.ID) (e *storage.Envelope, err error) { var sd scheduleData now := time.Now().UnixNano() err = d.db.Update(func(tx *bolt.Tx) error { ridx, err := tx.CreateBucketIfNotExists(bucketReplyIndex) if err != nil { return err } schedule := tx.Bucket(bucketSchedule) if schedule == nil { return ErrBucketNotFound } message := tx.Bucket(bucketMessage) if schedule == nil { return ErrBucketNotFound } c := schedule.Cursor() for k, v := c.First(); k != nil; k, v = c.Next() { skey := scheduleKey(k) sval := scheduleData(v) if skey.timestamp() > now { return storage.ErrEmpty } if !sval.retry().IsValid() { var envelope *storage.Envelope if b := message.Get(sval.messageID()); b != nil { envelope, _ = reconstruct(sval, b) } if err := schedule.Delete(k); err != nil { return err } if envelope != nil { event.Emit(event.EventMessageDiscarded, envelope) } continue } if skey.queue() == queue { newkey := scheduleKey(cloneBytes(k)) sd = scheduleData(cloneBytes(v)) if err := schedule.Delete(k); err != nil { return err } nextTick := now + sd.timeout() newkey.setTimestamp(nextTick) newkey.setAccumlating(false) retry := sd.retry() retry.Decr() sd.setRetry(retry) if err := schedule.Put(newkey, sd); err != nil { return err } return ridx.Put(eid.Bytes(), newReplyData(sd.messageID(), scheduleKey(newkey))) } } return storage.ErrEmpty }) if err != nil { return } var data []byte err = d.db.View(func(tx *bolt.Tx) error { bucket := tx.Bucket(bucketMessage) if bucket == nil { return ErrBucketNotFound } b := bucket.Get(sd.messageID()) if b == nil { return ErrMessageNotFound } data = cloneBytes(b) return nil }) if err != nil { return } return reconstruct(sd, data) }
func (d *Driver) Enqueue(queue string, id uid.ID, e *storage.Envelope, opts *storage.EnqueueOptions) (*storage.EnqueueMeta, error) { msg, err := marshal(e) if err != nil { return nil, err } var meta storage.EnqueueMeta if opts.AccumTime > 0 { now := time.Now().UnixNano() err = d.db.Update(func(tx *bolt.Tx) error { schedule := tx.Bucket(bucketSchedule) message := tx.Bucket(bucketMessage) if schedule == nil || message == nil { return ErrBucketNotFound } c := schedule.Cursor() for k, v := c.First(); k != nil; k, v = c.Next() { sk := scheduleKey(k) if sk.timestamp() <= now { continue } if sk.queue() == queue && sk.accumlating() { sd := scheduleData(v) b := message.Get(sd.messageID()) if b == nil { continue } meta.AccumState = storage.AccumAdded data := make([]byte, len(b)+len(msg)) n := copy(data, b) copy(data[n:], msg) return message.Put(sd.messageID(), data) } } return ErrMessageNotFound }) switch err { case nil: return &meta, nil case ErrMessageNotFound, ErrBucketNotFound: default: return nil, err } } skey := newScheduleKey(queue) if opts.AccumTime > 0 { skey.setAccumlating(true) meta.AccumState = storage.AccumStarted } sval := newScheduleData(id, int32(e.Retry), int64(e.Timeout)) for { t := time.Now().UnixNano() if opts.AccumTime > 0 { t += int64(opts.AccumTime) } skey.setTimestamp(t) err := d.db.Update(func(tx *bolt.Tx) error { message, err := tx.CreateBucketIfNotExists(bucketMessage) if err != nil { return err } schedule, err := tx.CreateBucketIfNotExists(bucketSchedule) if err != nil { return err } val := schedule.Get(skey) if val != nil { return errConflict } if err = message.Put(id.Bytes(), msg); err != nil { return err } return schedule.Put(skey, sval) }) if err == errConflict { continue } else if err == nil && opts.AccumTime == 0 { event.Emit(event.EventMessageAvailable, queue) } return &meta, err } }