/** * Execute the supplied operation using the primary, blocking until a primary is available. Whenever the operation stops * (e.g., if the primary is no longer primary), then restart the operation using the current primary. * * @param desc the description of the operation, for logging purposes * @param operation the operation to be performed on the primary * @return return value of the executed operation */ public <T> T execute(String desc, Function<MongoClient, T> operation) { final Metronome errorMetronome = Metronome.sleeper(PAUSE_AFTER_ERROR, Clock.SYSTEM); while (true) { MongoClient primary = primaryConnectionSupplier.get(); try { return operation.apply(primary); } catch (Throwable t) { errorHandler.accept(desc, t); if (!isRunning()) { throw new ConnectException("Operation failed and MongoDB primary termination requested", t); } try { errorMetronome.pause(); } catch (InterruptedException e) { // Interruption is not propagated } } } }
private void delaySnapshotIfNeeded() throws InterruptedException { Duration delay = Duration.ofMillis(context.getConnectionContext().config.getLong(CommonConnectorConfig.SNAPSHOT_DELAY_MS)); if (delay.isZero() || delay.isNegative()) { return; } Threads.Timer timer = Threads.timer(Clock.SYSTEM, delay); Metronome metronome = Metronome.parker(ConfigurationDefaults.RETURN_CONTROL_INTERVAL, Clock.SYSTEM); while(!timer.expired()) { if (!running.get()) { throw new InterruptedException("Interrupted while awaiting initial snapshot delay"); } logger.info("The connector will wait for {}s before proceeding", timer.remaining().getSeconds()); metronome.pause(); } }
/** * Does nothing until the connector task is shut down, but regularly returns control back to Connect in order for being paused if requested. */ @Override public List<SourceRecord> poll() throws InterruptedException { if (state.get() == State.STOPPED) { return null; } metronome.pause(); state.compareAndSet(State.RUNNING, State.STOPPING); return null; }
private ChangeEventQueue(Duration pollInterval, int maxQueueSize, int maxBatchSize, Supplier<LoggingContext.PreviousContext> loggingContextSupplier) { this.pollInterval = pollInterval; this.maxBatchSize = maxBatchSize; this.queue = new LinkedBlockingDeque<>(maxQueueSize); this.metronome = Metronome.sleeper(pollInterval, Clock.SYSTEM); this.loggingContextSupplier = loggingContextSupplier; }
public BlockingReader(String name, String runningLogMessage) { this.name = name; this.metronome = Metronome.parker(ConfigurationDefaults.RETURN_CONTROL_INTERVAL, Clock.SYSTEM); this.runningLogMessage = runningLogMessage; }
metronome.pause(); } catch (InterruptedException e) { Thread.currentThread().interrupt();
public static Metronome sleeper(Duration period, Clock timeSystem) { return sleeper(period.toNanos(), TimeUnit.NANOSECONDS, timeSystem); }
public static Metronome parker(Duration period, Clock timeSystem) { return parker(period.toNanos(), TimeUnit.NANOSECONDS, timeSystem); } }
/** * Execute the supplied operation using the primary, blocking until a primary is available. Whenever the operation stops * (e.g., if the primary is no longer primary), then restart the operation using the current primary. * * @param desc the description of the operation, for logging purposes * @param operation the operation to be performed on the primary. */ public void execute(String desc, Consumer<MongoClient> operation) { final Metronome errorMetronome = Metronome.sleeper(PAUSE_AFTER_ERROR, Clock.SYSTEM); while (true) { MongoClient primary = primaryConnectionSupplier.get(); try { operation.accept(primary); return; } catch (Throwable t) { errorHandler.accept(desc, t); if (!isRunning()) { throw new ConnectException("Operation failed and MongoDB primary termination requested", t); } try { errorMetronome.pause(); } catch (InterruptedException e) { // Interruption is not propagated } } } }
private void delaySnapshotIfNeeded() { Duration delay = taskContext.getConfig().getSnapshotDelay(); if (delay.isZero() || delay.isNegative()) { return; } Threads.Timer timer = Threads.timer(Clock.SYSTEM, delay); Metronome metronome = Metronome.parker(ConfigurationDefaults.RETURN_CONTROL_INTERVAL, Clock.SYSTEM); while (!timer.expired()) { try { logger.info("The connector will wait for {}s before proceeding", timer.remaining().getSeconds()); metronome.pause(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.debug("Interrupted while awaiting initial snapshot delay"); return; } } }
while (running.get() && (records.drainTo(batch, maxBatchSize) == 0) && !success.get()) { metronome.pause();
/** * @param monitor the component used to periodically obtain the replica set specifications; may not be null * @param period the time period between polling checks; must be non-negative * @param unit the time unit for the {@code period}; may not be null * @param clock the clock to use; may be null if the system clock should be used * @param onStartup the function to call when the thread is started; may be null if not needed * @param onChange the function to call when the set of replica set specifications has changed; may be null if not needed */ public ReplicaSetMonitorThread(Supplier<ReplicaSets> monitor, long period, TimeUnit unit, Clock clock, Runnable onStartup, Consumer<ReplicaSets> onChange) { if (clock == null) clock = Clock.system(); this.monitor = monitor; this.metronome = Metronome.sleeper(period, unit, clock); this.onChange = onChange != null ? onChange : (rsSpecs) -> {}; this.onStartup = onStartup != null ? onStartup : () -> {}; }
/** * Create a snapshot reader. * * @param name the name of the reader * @param context the task context in which this reader is running; may not be null * @param acceptAndContinue a predicate that returns true if the tested {@link SourceRecord} should be accepted and * false if the record and all subsequent records should be ignored. The reader will stop * accepting records once {@link #enqueueRecord(SourceRecord)} is called with a record * that tests as false. Can be null. If null, all records will be accepted. */ public AbstractReader(String name, MySqlTaskContext context, HaltingPredicate acceptAndContinue) { this.name = name; this.context = context; this.connectionContext = context.getConnectionContext(); this.records = new LinkedBlockingDeque<>(context.getConnectorConfig().getMaxQueueSize()); this.maxBatchSize = context.getConnectorConfig().getMaxBatchSize(); this.pollInterval = context.getConnectorConfig().getPollInterval(); this.metronome = Metronome.parker(pollInterval, Clock.SYSTEM); this.acceptAndContinue = acceptAndContinue == null? new AcceptAllPredicate() : acceptAndContinue; }
/** * Execute the supplied operation using the primary, blocking until a primary is available. Whenever the operation stops * (e.g., if the primary is no longer primary), then restart the operation using the current primary. * * @param desc the description of the operation, for logging purposes * @param operation the operation to be performed on the primary. * @throws InterruptedException if the operation was interrupted */ public void executeBlocking(String desc, BlockingConsumer<MongoClient> operation) throws InterruptedException { final Metronome errorMetronome = Metronome.sleeper(PAUSE_AFTER_ERROR, Clock.SYSTEM); while (true) { MongoClient primary = primaryConnectionSupplier.get(); try { operation.accept(primary); return; } catch (InterruptedException e) { throw e; } catch (Throwable t) { errorHandler.accept(desc, t); if (!isRunning()) { throw new ConnectException("Operation failed and MongoDB primary termination requested", t); } errorMetronome.pause(); } } }
protected ServerInfo.ReplicationSlot readReplicationSlotInfo(String slotName, String pluginName) throws SQLException, InterruptedException { final String database = database(); final Metronome metronome = Metronome.parker(PAUSE_BETWEEN_REPLICATION_SLOT_RETRIEVAL_ATTEMPTS, Clock.SYSTEM); metronome.pause();
/** * Returns the next batch of elements from this queue. May be empty in case no * elements have arrived in the maximum waiting time. * * @throws InterruptedException * if this thread has been interrupted while waiting for more * elements to arrive */ public List<T> poll() throws InterruptedException { LoggingContext.PreviousContext previousContext = loggingContextSupplier.get(); try { LOGGER.debug("polling records..."); List<T> records = new ArrayList<>(); final Timer timeout = Threads.timer(Clock.SYSTEM, Temporals.max(pollInterval, ConfigurationDefaults.RETURN_CONTROL_INTERVAL)); while (!timeout.expired() && queue.drainTo(records, maxBatchSize) == 0) { throwProducerFailureIfPresent(); LOGGER.debug("no records available yet, sleeping a bit..."); // no records yet, so wait a bit metronome.pause(); LOGGER.debug("checking for more records..."); } return records; } finally { previousContext.restore(); } }
private ChangeEventQueue(Duration pollInterval, int maxQueueSize, int maxBatchSize, Supplier<LoggingContext.PreviousContext> loggingContextSupplier) { this.pollInterval = pollInterval; this.maxBatchSize = maxBatchSize; this.maxQueueSize = maxQueueSize; this.queue = new LinkedBlockingDeque<>(maxQueueSize); this.metronome = Metronome.sleeper(pollInterval, Clock.SYSTEM); this.loggingContextSupplier = loggingContextSupplier; }
public static Metronome parker(Duration period, Clock timeSystem) { return parker(period.toNanos(), TimeUnit.NANOSECONDS, timeSystem); } }
public static void waitForSnapshotToBeCompleted() throws InterruptedException { int waitForSeconds = 60; final MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); final Metronome metronome = Metronome.sleeper(Duration.ofSeconds(1), Clock.system()); while (true) { if (waitForSeconds-- <= 0) { Assert.fail("Snapshot was not completed on time"); } try { final boolean completed = (boolean)mbeanServer.getAttribute(new ObjectName("debezium.sql_server:type=connector-metrics,context=snapshot,server=server1"), "SnapshotCompleted"); if (completed) { break; } } catch (InstanceNotFoundException e) { // Metrics has not started yet } catch (Exception e) { throw new IllegalStateException(e); } metronome.pause(); } } }
/** * Delays snapshot execution as per the {@link CommonConnectorConfig#SNAPSHOT_DELAY_MS} parameter. */ private void delaySnapshotIfNeeded(ChangeEventSourceContext context) throws InterruptedException { Duration snapshotDelay = connectorConfig.getSnapshotDelay(); if (snapshotDelay.isZero() || snapshotDelay.isNegative()) { return; } Timer timer = Threads.timer(Clock.SYSTEM, snapshotDelay); Metronome metronome = Metronome.parker(ConfigurationDefaults.RETURN_CONTROL_INTERVAL, Clock.SYSTEM); while(!timer.expired()) { if (!context.isRunning()) { throw new InterruptedException("Interrupted while awaiting initial snapshot delay"); } LOGGER.info("The connector will wait for {}s before proceeding", timer.remaining().getSeconds()); metronome.pause(); } }