private Cancellable scheduleReconnect() { final FiniteDuration initialDelay = FiniteDuration.apply(reconnectInitialDelay.toMillis(), TimeUnit.MILLISECONDS); final FiniteDuration interval = FiniteDuration.apply(reconnectInterval.toMillis(), TimeUnit.MILLISECONDS); final ReconnectMessages message = ReconnectMessages.START_RECONNECT; log.info("Scheduling reconnect for all connections with initial delay {} and interval {}.", reconnectInitialDelay, reconnectInterval); return getContext().getSystem() .scheduler() .schedule(initialDelay, interval, getSelf(), message, getContext().dispatcher(), ActorRef.noSender()); }
@Override public void preStart() throws Exception { super.preStart(); reconnectCheck = scheduleReconnect(); }
private void reconnect(final String persistenceId) { // yes, this is intentionally a RetrieveConnectionStatus instead of OpenConnection. // ConnectionActor manages its own reconnection on recovery. // OpenConnection would set desired state to OPEN even for deleted connections. if (persistenceId.startsWith(ConnectionActor.PERSISTENCE_ID_PREFIX)) { final String connectionId = persistenceId.substring(ConnectionActor.PERSISTENCE_ID_PREFIX.length()); final DittoHeaders dittoHeaders = DittoHeaders.newBuilder() .correlationId(toCorrelationId(connectionId)) .build(); log.debug("Sending a reconnect for Connection {}", connectionId); connectionShardRegion.tell(RetrieveConnectionStatus.of(connectionId, dittoHeaders), getSelf()); } else { log.debug("Unknown persistence id '{}', ignoring.", persistenceId); } }
@Override public Receive createReceive() { return ReceiveBuilder.create() .match(RetrieveConnectionStatusResponse.class, command -> log.debug("Retrieved connection status response for connection {} with status: {}", command.getConnectionId(), command.getConnectionStatus())) .match(ConnectionNotAccessibleException.class, exception -> log.debug("Received ConnectionNotAccessibleException for connection {} " + "(most likely, the connection was deleted): {}", exception.getDittoHeaders().getCorrelationId().orElse("<unknown>"), exception.getMessage())) .match(DittoRuntimeException.class, exception -> log.debug("Received {} for connection {} : {}", exception.getClass().getSimpleName(), exception.getDittoHeaders().getCorrelationId().orElse("<unknown>"), exception.getMessage())) .matchEquals(ReconnectMessages.START_RECONNECT, msg -> handleStartReconnect()) .matchEquals(ReconnectMessages.END_RECONNECT, msg -> handleEndReconnect()) .matchAny(m -> { log.warning("Unknown message: {}", m); unhandled(m); }).build(); }
private ReconnectActor(final ActorRef connectionShardRegion, final Supplier<Source<String, NotUsed>> currentPersistenceIdsSourceSupplier) { this.connectionShardRegion = connectionShardRegion; this.currentPersistenceIdsSourceSupplier = currentPersistenceIdsSourceSupplier; final Config config = getContext().system().settings().config(); materializer = ActorMaterializer.create(getContext().getSystem()); reconnectInitialDelay = config.getDuration(ConfigKeys.Reconnect.RECONNECT_INITIAL_DELAY); reconnectInterval = config.getDuration(ConfigKeys.Reconnect.RECONNECT_INTERVAL); reconnectRateFrequency = config.getDuration(ConfigKeys.Reconnect.RECONNECT_RATE_FREQUENCY); reconnectRateEntities = config.getInt(ConfigKeys.Reconnect.RECONNECT_RATE_ENTITIES); }
private void handleStartReconnect() { if (reconnectInProgress) { log.info("Another reconnect iteration is currently in progress. Next iteration will be started after {}.", reconnectInterval); } else { log.info("Sending reconnects for Connections. Will be sent again after the configured Interval of {}.", reconnectInterval); reconnectInProgress = true; final Source<String, NotUsed> currentPersistenceIdsSource = currentPersistenceIdsSourceSupplier.get(); if (currentPersistenceIdsSource != null) { currentPersistenceIdsSource .throttle(reconnectRateEntities, reconnectRateFrequency) .runForeach(this::reconnect, materializer) .thenRun(() -> { log.info("Sending reconnects completed."); getSelf().tell(ReconnectMessages.END_RECONNECT, getSelf()); }); } else { log.warning("Failed to create new persistence id source for connection recovery."); } } }
.getReadJournalFor(JavaDslMongoReadJournal.class, RECONNECT_READ_JOURNAL_PLUGIN_ID); startClusterSingletonActor(ReconnectActor.ACTOR_NAME, ReconnectActor.props(connectionShardRegion, mongoReadJournal::currentPersistenceIds));
@Override public Receive createReceive() { return ReceiveBuilder.create() .match(RetrieveConnectionStatusResponse.class, command -> log.debug("Retrieved connection status response for connection {} with status: {}", command.getConnectionId(), command.getConnectionStatus())) .match(ConnectionNotAccessibleException.class, exception -> log.debug("Received ConnectionNotAccessibleException for connection {} " + "(most likely, the connection was deleted): {}", exception.getDittoHeaders().getCorrelationId().orElse("<unknown>"), exception.getMessage())) .match(DittoRuntimeException.class, exception -> log.debug("Received {} for connection {} : {}", exception.getClass().getSimpleName(), exception.getDittoHeaders().getCorrelationId().orElse("<unknown>"), exception.getMessage())) .matchEquals(ReconnectMessages.START_RECONNECT, msg -> handleStartReconnect()) .matchEquals(ReconnectMessages.END_RECONNECT, msg -> handleEndReconnect()) .matchAny(m -> { log.warning("Unknown message: {}", m); unhandled(m); }).build(); }
private ReconnectActor(final ActorRef connectionShardRegion, final Supplier<Source<String, NotUsed>> currentPersistenceIdsSourceSupplier) { this.connectionShardRegion = connectionShardRegion; this.currentPersistenceIdsSourceSupplier = currentPersistenceIdsSourceSupplier; final Config config = getContext().system().settings().config(); materializer = ActorMaterializer.create(getContext().getSystem()); reconnectInitialDelay = config.getDuration(ConfigKeys.Reconnect.RECONNECT_INITIAL_DELAY); reconnectInterval = config.getDuration(ConfigKeys.Reconnect.RECONNECT_INTERVAL); reconnectRateFrequency = config.getDuration(ConfigKeys.Reconnect.RECONNECT_RATE_FREQUENCY); reconnectRateEntities = config.getInt(ConfigKeys.Reconnect.RECONNECT_RATE_ENTITIES); }
private void handleStartReconnect() { if (reconnectInProgress) { log.info("Another reconnect iteration is currently in progress. Next iteration will be started after {}.", reconnectInterval); } else { log.info("Sending reconnects for Connections. Will be sent again after the configured Interval of {}.", reconnectInterval); reconnectInProgress = true; final Source<String, NotUsed> currentPersistenceIdsSource = currentPersistenceIdsSourceSupplier.get(); if (currentPersistenceIdsSource != null) { currentPersistenceIdsSource .throttle(reconnectRateEntities, reconnectRateFrequency) .runForeach(this::reconnect, materializer) .thenRun(() -> { log.info("Sending reconnects completed."); getSelf().tell(ReconnectMessages.END_RECONNECT, getSelf()); }); } else { log.warning("Failed to create new persistence id source for connection recovery."); } } }
private Cancellable scheduleReconnect() { final FiniteDuration initialDelay = FiniteDuration.apply(reconnectInitialDelay.toMillis(), TimeUnit.MILLISECONDS); final FiniteDuration interval = FiniteDuration.apply(reconnectInterval.toMillis(), TimeUnit.MILLISECONDS); final ReconnectMessages message = ReconnectMessages.START_RECONNECT; log.info("Scheduling reconnect for all connections with initial delay {} and interval {}.", reconnectInitialDelay, reconnectInterval); return getContext().getSystem() .scheduler() .schedule(initialDelay, interval, getSelf(), message, getContext().dispatcher(), ActorRef.noSender()); }
private void reconnect(final String persistenceId) { // yes, this is intentionally a RetrieveConnectionStatus instead of OpenConnection. // ConnectionActor manages its own reconnection on recovery. // OpenConnection would set desired state to OPEN even for deleted connections. if (persistenceId.startsWith(ConnectionActor.PERSISTENCE_ID_PREFIX)) { final String connectionId = persistenceId.substring(ConnectionActor.PERSISTENCE_ID_PREFIX.length()); final DittoHeaders dittoHeaders = DittoHeaders.newBuilder() .correlationId(toCorrelationId(connectionId)) .build(); log.debug("Sending a reconnect for Connection {}", connectionId); connectionShardRegion.tell(RetrieveConnectionStatus.of(connectionId, dittoHeaders), getSelf()); } else { log.debug("Unknown persistence id '{}', ignoring.", persistenceId); } }
@Override public void preStart() throws Exception { super.preStart(); reconnectCheck = scheduleReconnect(); }