Beispiel #1
0
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
}
Beispiel #2
0
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
}
Beispiel #3
0
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)
}
Beispiel #4
0
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
	}
}