Search in sources :

Example 1 with StreamMessageId

use of org.redisson.api.StreamMessageId in project redisson by redisson.

the class RedissonReliableTopic method addListenerAsync.

@Override
public <M> RFuture<String> addListenerAsync(Class<M> type, MessageListener<M> listener) {
    String id = generateId();
    listeners.put(id, new Entry(type, listener));
    if (subscriberId.get() != null) {
        return RedissonPromise.newSucceededFuture(id);
    }
    if (subscriberId.compareAndSet(null, id)) {
        renewExpiration();
        StreamMessageId startId = StreamMessageId.ALL;
        RFuture<Void> addFuture = commandExecutor.evalWriteNoRetryAsync(getRawName(), StringCodec.INSTANCE, RedisCommands.EVAL_VOID, "local value = redis.call('incr', KEYS[3]); " + "redis.call('zadd', KEYS[4], ARGV[3], ARGV[2]); " + "redis.call('zadd', KEYS[1], value, ARGV[2]); " + "redis.call('hset', KEYS[2], ARGV[2], ARGV[1]); ", Arrays.asList(getSubscribersName(), getMapName(), getCounter(), getTimeout()), startId, id, System.currentTimeMillis() + commandExecutor.getConnectionManager().getCfg().getReliableTopicWatchdogTimeout());
        CompletionStage<String> f = addFuture.thenApply(r -> {
            poll(id, startId);
            return id;
        });
        return new CompletableFutureWrapper<>(f);
    }
    return RedissonPromise.newSucceededFuture(id);
}
Also used : CompletableFutureWrapper(org.redisson.misc.CompletableFutureWrapper) StreamMessageId(org.redisson.api.StreamMessageId)

Example 2 with StreamMessageId

use of org.redisson.api.StreamMessageId in project redisson by redisson.

the class RedissonReliableTopic method poll.

private void poll(String id, StreamMessageId startId) {
    readFuture = commandExecutor.readAsync(getRawName(), new CompositeCodec(StringCodec.INSTANCE, codec), RedisCommands.XREAD_BLOCKING_SINGLE, "BLOCK", 0, "STREAMS", getRawName(), startId);
    readFuture.whenComplete((res, ex) -> {
        if (readFuture.isCancelled()) {
            return;
        }
        if (ex != null) {
            if (ex instanceof RedissonShutdownException) {
                return;
            }
            log.error(ex.getMessage(), ex);
            commandExecutor.getConnectionManager().newTimeout(task -> {
                poll(id, startId);
            }, 1, TimeUnit.SECONDS);
            return;
        }
        commandExecutor.getConnectionManager().getExecutor().execute(() -> {
            res.values().forEach(entry -> {
                Object m = entry.get("m");
                listeners.values().forEach(e -> {
                    if (e.getType().isInstance(m)) {
                        ((MessageListener<Object>) e.getListener()).onMessage(getRawName(), m);
                    }
                });
            });
        });
        if (listeners.isEmpty()) {
            return;
        }
        StreamMessageId lastId = res.keySet().stream().skip(res.size() - 1).findFirst().get();
        long time = System.currentTimeMillis();
        RFuture<Boolean> updateFuture = commandExecutor.evalWriteAsync(getRawName(), StringCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN, "local r = redis.call('zscore', KEYS[2], ARGV[2]); " + "if r ~= false then " + "local value = redis.call('incr', KEYS[4]); " + "redis.call('zadd', KEYS[2], value, ARGV[2]); " + "redis.call('hset', KEYS[3], ARGV[2], ARGV[1]); " + "end; " + "local t = redis.call('zrange', KEYS[5], 0, 0, 'WITHSCORES'); " + "if tonumber(t[2]) < tonumber(ARGV[3]) then " + "redis.call('hdel', KEYS[3], t[1]); " + "redis.call('zrem', KEYS[2], t[1]); " + "redis.call('zrem', KEYS[5], t[1]); " + "end; " + "local v = redis.call('zrange', KEYS[2], 0, 0); " + "local score = redis.call('hget', KEYS[3], v[1]); " + "local range = redis.call('xrange', KEYS[1], score, '+'); " + "if #range == 0 then " + "redis.call('del', KEYS[1]); " + "elseif #range == 1 and range[1][1] == score then " + "redis.call('del', KEYS[1]); " + "else " + "redis.call('xtrim', KEYS[1], 'maxlen', #range); " + "end;" + "return r ~= false; ", Arrays.asList(getRawName(), getSubscribersName(), getMapName(), getCounter(), getTimeout()), lastId, id, time);
        updateFuture.whenComplete((re, exc) -> {
            if (exc != null) {
                if (exc instanceof RedissonShutdownException) {
                    return;
                }
                log.error("Unable to update subscriber status", exc);
                return;
            }
            if (!re || listeners.isEmpty()) {
                return;
            }
            poll(id, lastId);
        });
    });
}
Also used : CompositeCodec(org.redisson.codec.CompositeCodec) MessageListener(org.redisson.api.listener.MessageListener) StreamMessageId(org.redisson.api.StreamMessageId)

Example 3 with StreamMessageId

use of org.redisson.api.StreamMessageId in project redisson by redisson.

the class StreamInfoDecoder method createStreamInfoEntry.

private StreamInfo.Entry<Object, Object> createStreamInfoEntry(List<?> fieldValue) {
    StreamMessageId id = StreamIdConvertor.INSTANCE.convert(fieldValue.get(0));
    Map<Object, Object> data = (Map<Object, Object>) fieldValue.get(1);
    return new StreamInfo.Entry<>(id, data);
}
Also used : Map(java.util.Map) StreamMessageId(org.redisson.api.StreamMessageId)

Aggregations

StreamMessageId (org.redisson.api.StreamMessageId)3 Map (java.util.Map)1 MessageListener (org.redisson.api.listener.MessageListener)1 CompositeCodec (org.redisson.codec.CompositeCodec)1 CompletableFutureWrapper (org.redisson.misc.CompletableFutureWrapper)1