Beispiel #1
0
// UpdateQueues should be called whenever a client changes what queues it's
// registered for. The new full list of registered queues should be passed in,
// this method will do a diff and figure it out what was removed
func UpdateQueues(client *clients.Client, queues []string) error {
	respCh := make(chan error)
	callCh <- func(s *state) {
		oldQueues := s.clientQueues(client.ID)
		removed := stringSliceSub(oldQueues, queues)
		s.addClientQueues(client, queues)
		s.removeClientQueues(client, removed)

		select {
		case updateNotifyCh <- struct{}{}:
		default:
		}

		ts := time.Now().Unix()
		pipe := make([]*db.PipePart, 0, len(removed)+len(queues))

		for _, queueName := range removed {
			consumersKey := db.ConsumersKey(queueName)
			pipe = append(pipe, db.PP("ZREM", consumersKey, client.ID))
		}
		for _, queueName := range queues {
			consumersKey := db.ConsumersKey(queueName)
			pipe = append(pipe, db.PP("ZADD", consumersKey, ts, client.ID))
		}

		_, err := db.Inst.Pipe(pipe...)
		respCh <- err
	}
	return <-respCh
}
Beispiel #2
0
func qpushgeneric(
	_ *clients.Client, args []string, pushRight bool,
) (
	interface{}, error,
) {
	queueName, eventID, contents := args[0], args[1], args[2]
	restArgs := args[3:]
	if len(restArgs) > 0 && isEqualUpper("NOBLOCK", restArgs[0]) {
		coreArgs := args[:3]
		select {
		case qpushBGCh <- &qpushBG{coreArgs, pushRight}:
			return okSS, nil
		default:
			return fmt.Errorf("ERR too busy to process NOBLOCK event"), nil
		}
	}

	itemsKey := db.ItemsKey(queueName)

	created, err := db.Inst.Cmd("HSETNX", itemsKey, eventID, contents).Int()
	if err != nil {
		return nil, fmt.Errorf("QPUSH* HSETNX: %s", err)
	} else if created == 0 {
		return fmt.Errorf("ERR duplicate event %s", eventID), nil
	}

	unclaimedKey := db.UnclaimedKey(queueName)
	cmd := "LPUSH"
	if pushRight {
		cmd = "RPUSH"
	}
	channelName := db.QueueChannelNameKey(queueName)

	_, err = db.Inst.Pipe(
		db.PP(cmd, unclaimedKey, eventID),
		db.PP("PUBLISH", channelName, eventID),
	)
	if err != nil {
		return nil, fmt.Errorf("QPUSH* %s/PUBLISH: %s", cmd, err)
	}

	return okSS, nil
}
Beispiel #3
0
func qack(client *clients.Client, args []string) (interface{}, error) {
	queueName, eventID := args[0], args[1]
	claimedKey := db.ClaimedKey(queueName)

	var numRemoved int
	numRemoved, err := db.Inst.Cmd("LREM", claimedKey, -1, eventID).Int()
	if err != nil {
		return nil, fmt.Errorf("QACK LREM (claimed): %s", err)
	}

	// If we didn't removed the eventID from the claimed events we see if it can
	// be found in unclaimed. We only do this in the uncommon case that the
	// eventID isn't in claimed since unclaimed can be really large, so LREM is
	// slow on it
	if numRemoved == 0 {
		unclaimedKey := db.UnclaimedKey(queueName)
		var err error
		numRemoved, err = db.Inst.Cmd("LREM", unclaimedKey, -1, eventID).Int()
		if err != nil {
			return nil, fmt.Errorf("QACK LREM (unclaimed): %s", err)
		}
	}

	// We only remove the object data itself if the eventID was actually removed
	// from something
	if numRemoved > 0 {
		itemsKey := db.ItemsKey(queueName)
		lockKey := db.ItemLockKey(queueName, eventID)
		_, err := db.Inst.Pipe(
			db.PP("HDEL", itemsKey, eventID),
			db.PP("DEL", lockKey),
		)
		if err != nil {
			return nil, fmt.Errorf("QACK HDEL/DEL: %s", err)
		}
	}

	return numRemoved, nil
}