@flowcore/data-pump 0.22.1 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +313 -191
- package/dist/mod.d.ts +147 -16
- package/dist/mod.js +623 -170
- package/package.json +1 -1
package/dist/mod.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FlowcoreEvent, FlowcoreClient, EventListOutput } from '@flowcore/sdk';
|
|
2
|
-
import
|
|
2
|
+
import { Registry, Gauge, Counter, Histogram } from 'prom-client';
|
|
3
3
|
import * as Nats from 'nats';
|
|
4
4
|
|
|
5
5
|
type FlowcoreDataPumpAuth = {
|
|
@@ -89,6 +89,8 @@ declare class FlowcoreDataSource {
|
|
|
89
89
|
protected eventTypeIds?: string[];
|
|
90
90
|
/** Cached time buckets */
|
|
91
91
|
protected timeBuckets?: string[];
|
|
92
|
+
/** Index for each cached bucket. */
|
|
93
|
+
private timeBucketIndexes;
|
|
92
94
|
/**
|
|
93
95
|
* Creates a new FlowcoreDataSource instance
|
|
94
96
|
* @param options - Configuration options for the data source
|
|
@@ -141,6 +143,8 @@ declare class FlowcoreDataSource {
|
|
|
141
143
|
* @returns Promise that resolves to an array of time bucket strings
|
|
142
144
|
*/
|
|
143
145
|
getTimeBuckets(force?: boolean): Promise<string[]>;
|
|
146
|
+
private lowerBoundTimeBucket;
|
|
147
|
+
private upperBoundTimeBucket;
|
|
144
148
|
/**
|
|
145
149
|
* Gets the next time bucket after the specified time bucket
|
|
146
150
|
* @param timeBucket - The reference time bucket
|
|
@@ -186,6 +190,8 @@ interface PulseSnapshot {
|
|
|
186
190
|
timeBucket: string;
|
|
187
191
|
eventId: string | undefined;
|
|
188
192
|
isLive: boolean;
|
|
193
|
+
/** Delivery to the processor is paused. The pump is still fetching and alive. */
|
|
194
|
+
paused: boolean;
|
|
189
195
|
bufferDepth: number;
|
|
190
196
|
bufferReserved: number;
|
|
191
197
|
bufferSizeBytes: number;
|
|
@@ -237,6 +243,14 @@ interface FlowcoreDataPumpOptions {
|
|
|
237
243
|
notifier?: FlowcoreDataPumpNotifierOptions;
|
|
238
244
|
logger?: FlowcoreLogger;
|
|
239
245
|
stopAt?: Date;
|
|
246
|
+
/**
|
|
247
|
+
* Start the pump with delivery already paused.
|
|
248
|
+
*
|
|
249
|
+
* Use this to restore a pause that is stored somewhere durable. Calling `pause()`
|
|
250
|
+
* after `start()` would let the pump deliver events in the gap between the two.
|
|
251
|
+
* Ignored when no `processor` is configured, for the same reason as {@link FlowcoreDataPump.pause}.
|
|
252
|
+
*/
|
|
253
|
+
paused?: boolean;
|
|
240
254
|
baseUrlOverride?: string;
|
|
241
255
|
noTranslation?: boolean;
|
|
242
256
|
directMode?: boolean;
|
|
@@ -259,7 +273,12 @@ declare class FlowcoreDataPump {
|
|
|
259
273
|
private readonly logger?;
|
|
260
274
|
private nextCursor?;
|
|
261
275
|
private running;
|
|
276
|
+
private paused;
|
|
262
277
|
private restartTo?;
|
|
278
|
+
private processLoopGeneration;
|
|
279
|
+
private activeProcessLoopGeneration?;
|
|
280
|
+
private processLoopBackoffGeneration?;
|
|
281
|
+
private processLoopRestartTimer?;
|
|
263
282
|
private abortController?;
|
|
264
283
|
private buffer;
|
|
265
284
|
private bufferState;
|
|
@@ -273,30 +292,75 @@ declare class FlowcoreDataPump {
|
|
|
273
292
|
private pulledCount;
|
|
274
293
|
private processLoopRestartAttempts;
|
|
275
294
|
private mainLoopRestartAttempts;
|
|
295
|
+
private readonly replayObserver;
|
|
296
|
+
private readonly bufferStats;
|
|
297
|
+
private bufferReservedCount;
|
|
298
|
+
private bufferSizeBytes;
|
|
299
|
+
private gaugePublicationScheduled;
|
|
276
300
|
private constructor();
|
|
301
|
+
/**
|
|
302
|
+
* Whether delivery to the processor is currently paused.
|
|
303
|
+
* A paused pump is still running: it fetches, buffers and pulses.
|
|
304
|
+
*/
|
|
305
|
+
get isPaused(): boolean;
|
|
277
306
|
get isRunning(): boolean;
|
|
278
307
|
getSnapshot(): PulseSnapshot | null;
|
|
279
308
|
static create(options: FlowcoreDataPumpOptions, dataSourceOverride?: FlowcoreDataSource): FlowcoreDataPump;
|
|
280
309
|
start(callback?: (error?: Error) => void): Promise<void>;
|
|
281
310
|
private startMainLoop;
|
|
282
311
|
restart(state: FlowcoreDataPumpState, stopAt?: Date | null): void;
|
|
312
|
+
/**
|
|
313
|
+
* Pause delivery to the processor.
|
|
314
|
+
*
|
|
315
|
+
* The fetch loop keeps running and tops the buffer up to `bufferSize`, then blocks on
|
|
316
|
+
* normal backpressure. The buffer, the cursor and the pulse emitter are untouched, so
|
|
317
|
+
* the control plane still sees a live pump. An in-flight batch finishes its handler
|
|
318
|
+
* and acknowledges, so the checkpoint stays accurate and nothing is redelivered
|
|
319
|
+
* needlessly.
|
|
320
|
+
*
|
|
321
|
+
* Idempotent. A paused pump holds up to `bufferSize` events in memory.
|
|
322
|
+
*/
|
|
323
|
+
pause(): void;
|
|
324
|
+
/**
|
|
325
|
+
* Resume delivery to the processor from the exact position where {@link pause} stopped it.
|
|
326
|
+
* Idempotent.
|
|
327
|
+
*/
|
|
328
|
+
resume(): void;
|
|
283
329
|
stop(isRestart?: boolean): void;
|
|
284
330
|
private updateState;
|
|
285
331
|
private loop;
|
|
286
332
|
reserve(amount: number): Promise<FlowcoreEvent[]>;
|
|
333
|
+
private reserveInternal;
|
|
287
334
|
onFinalyFailed(handler: (events: FlowcoreEvent[]) => Promise<void> | void): void;
|
|
288
335
|
acknowledge(eventIds: string[]): Promise<void>;
|
|
289
336
|
fail(eventIds: string[]): Promise<void>;
|
|
290
337
|
private reOpen;
|
|
338
|
+
/**
|
|
339
|
+
* Guarantee a live process loop whenever the pump is running with a
|
|
340
|
+
* processor. Called from the fetch loop, so a delivery loop that exited for
|
|
341
|
+
* any reason — most importantly a restart, which clears `running` while the
|
|
342
|
+
* loop is mid-batch — comes back within one fetch iteration instead of
|
|
343
|
+
* leaving a pump that pulls but never delivers.
|
|
344
|
+
*/
|
|
345
|
+
private ensureProcessLoop;
|
|
291
346
|
private startProcessLoop;
|
|
347
|
+
private isCurrentProcessLoop;
|
|
292
348
|
private processLoop;
|
|
349
|
+
private addEventsToBuffer;
|
|
350
|
+
private updateReservedStats;
|
|
351
|
+
private removeFromBufferStats;
|
|
352
|
+
private resetBufferStats;
|
|
293
353
|
private updateMetricsGauges;
|
|
354
|
+
private publishMetricsGauges;
|
|
294
355
|
private incMetricsCounter;
|
|
295
|
-
private
|
|
356
|
+
private publicEventWaiter?;
|
|
357
|
+
private readonly processEventWaiters;
|
|
358
|
+
private notifyEventWaiters;
|
|
296
359
|
private waitForEvents;
|
|
297
360
|
private waiterBufferThreshold?;
|
|
298
361
|
private waitForBufferThreshold;
|
|
299
362
|
private waiterBufferEmpty?;
|
|
363
|
+
private notifyBufferEmpty;
|
|
300
364
|
private waitForBufferEmpty;
|
|
301
365
|
}
|
|
302
366
|
|
|
@@ -321,6 +385,7 @@ declare class FlowcoreDataPumpCluster {
|
|
|
321
385
|
private readonly logger?;
|
|
322
386
|
private running;
|
|
323
387
|
private isLeader;
|
|
388
|
+
private paused;
|
|
324
389
|
private pump?;
|
|
325
390
|
private leaderConnection?;
|
|
326
391
|
private workers;
|
|
@@ -372,6 +437,21 @@ declare class FlowcoreDataPumpCluster {
|
|
|
372
437
|
*/
|
|
373
438
|
handleConnection(ws: WebSocket): void;
|
|
374
439
|
start(): Promise<void>;
|
|
440
|
+
/**
|
|
441
|
+
* Whether delivery is paused across the cluster.
|
|
442
|
+
* The flag lives on the cluster, so it survives a leader change.
|
|
443
|
+
*/
|
|
444
|
+
get isPaused(): boolean;
|
|
445
|
+
/**
|
|
446
|
+
* Pause delivery. A leader applies it to its pump immediately. A follower records it,
|
|
447
|
+
* so the pause is re-applied if this instance later becomes leader.
|
|
448
|
+
*
|
|
449
|
+
* The flag is in-memory. It does NOT survive a process restart or a full rolling
|
|
450
|
+
* deploy — persist it in the coordinator or the control plane if you need that.
|
|
451
|
+
*/
|
|
452
|
+
pause(): void;
|
|
453
|
+
/** Resume delivery from the position where {@link pause} stopped it. */
|
|
454
|
+
resume(): void;
|
|
375
455
|
stop(): Promise<void>;
|
|
376
456
|
private startHeartbeat;
|
|
377
457
|
private startElectionLoop;
|
|
@@ -392,22 +472,73 @@ declare class FlowcoreDataPumpCluster {
|
|
|
392
472
|
private handleWorkerMessage;
|
|
393
473
|
}
|
|
394
474
|
|
|
395
|
-
declare const dataPumpPromRegistry:
|
|
475
|
+
declare const dataPumpPromRegistry: Registry<"text/plain; version=0.0.4; charset=utf-8">;
|
|
476
|
+
declare const REPLAY_DURATION_BUCKETS_SECONDS: readonly [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2, 5, 10, 20, 30, 60, 120];
|
|
477
|
+
declare const REPLAY_EVENT_COUNT_BUCKETS: readonly [1, 10, 50, 100, 250, 500, 1000, 2000, 5000, 10000];
|
|
478
|
+
declare const REPLAY_BATCH_SIZE_BUCKETS: readonly ["empty", "1", "2-10", "11-100", "101-1000", "1001+"];
|
|
479
|
+
declare const REPLAY_FETCH_RESULTS: readonly ["success", "no_events", "error"];
|
|
480
|
+
declare const REPLAY_STAGE_RESULTS: readonly ["success", "error"];
|
|
481
|
+
declare const REPLAY_IDLE_REASONS: readonly ["no_events", "buffer_full", "waiting_for_events"];
|
|
482
|
+
type ReplayBatchSizeBucket = (typeof REPLAY_BATCH_SIZE_BUCKETS)[number];
|
|
483
|
+
type ReplayIdleReason = (typeof REPLAY_IDLE_REASONS)[number];
|
|
484
|
+
type ReplaySourceLabels = {
|
|
485
|
+
tenant: string;
|
|
486
|
+
data_core: string;
|
|
487
|
+
flow_type: string;
|
|
488
|
+
};
|
|
489
|
+
declare function replayBatchSizeBucket(size: number): ReplayBatchSizeBucket;
|
|
490
|
+
declare function createDataPumpMetrics(registry: Registry, includeDefaultRegistry?: boolean): {
|
|
491
|
+
bufferEventCountGauge: Gauge<"tenant" | "data_core" | "flow_type" | "event_type">;
|
|
492
|
+
bufferReservedEventCountGauge: Gauge<"tenant" | "data_core" | "flow_type" | "event_type">;
|
|
493
|
+
bufferSizeBytesGauge: Gauge<"tenant" | "data_core" | "flow_type" | "event_type">;
|
|
494
|
+
eventsAcknowledgedCounter: Counter<"tenant" | "data_core" | "flow_type" | "event_type">;
|
|
495
|
+
eventsFailedCounter: Counter<"tenant" | "data_core" | "flow_type" | "event_type">;
|
|
496
|
+
eventsPulledSizeBytesCounter: Counter<"tenant" | "data_core" | "flow_type" | "event_type">;
|
|
497
|
+
sdkCommandsCounter: Counter<"command">;
|
|
498
|
+
replayFetchDuration: Histogram<"tenant" | "data_core" | "flow_type" | "result">;
|
|
499
|
+
replayFetchEvents: Histogram<"tenant" | "data_core" | "flow_type">;
|
|
500
|
+
replayHandlerDuration: Histogram<"tenant" | "data_core" | "flow_type" | "result" | "batch_size_bucket">;
|
|
501
|
+
replayAcknowledgementDuration: Histogram<"tenant" | "data_core" | "flow_type" | "result">;
|
|
502
|
+
replayCheckpointDuration: Histogram<"tenant" | "data_core" | "flow_type" | "result">;
|
|
503
|
+
replayIdleDuration: Histogram<"tenant" | "data_core" | "flow_type" | "reason">;
|
|
504
|
+
};
|
|
505
|
+
type DataPumpMetrics = ReturnType<typeof createDataPumpMetrics>;
|
|
396
506
|
declare const metrics: {
|
|
397
|
-
bufferEventCountGauge:
|
|
398
|
-
bufferReservedEventCountGauge:
|
|
399
|
-
bufferSizeBytesGauge:
|
|
400
|
-
eventsAcknowledgedCounter:
|
|
401
|
-
eventsFailedCounter:
|
|
402
|
-
eventsPulledSizeBytesCounter:
|
|
403
|
-
sdkCommandsCounter:
|
|
507
|
+
bufferEventCountGauge: Gauge<"tenant" | "data_core" | "flow_type" | "event_type">;
|
|
508
|
+
bufferReservedEventCountGauge: Gauge<"tenant" | "data_core" | "flow_type" | "event_type">;
|
|
509
|
+
bufferSizeBytesGauge: Gauge<"tenant" | "data_core" | "flow_type" | "event_type">;
|
|
510
|
+
eventsAcknowledgedCounter: Counter<"tenant" | "data_core" | "flow_type" | "event_type">;
|
|
511
|
+
eventsFailedCounter: Counter<"tenant" | "data_core" | "flow_type" | "event_type">;
|
|
512
|
+
eventsPulledSizeBytesCounter: Counter<"tenant" | "data_core" | "flow_type" | "event_type">;
|
|
513
|
+
sdkCommandsCounter: Counter<"command">;
|
|
514
|
+
replayFetchDuration: Histogram<"tenant" | "data_core" | "flow_type" | "result">;
|
|
515
|
+
replayFetchEvents: Histogram<"tenant" | "data_core" | "flow_type">;
|
|
516
|
+
replayHandlerDuration: Histogram<"tenant" | "data_core" | "flow_type" | "result" | "batch_size_bucket">;
|
|
517
|
+
replayAcknowledgementDuration: Histogram<"tenant" | "data_core" | "flow_type" | "result">;
|
|
518
|
+
replayCheckpointDuration: Histogram<"tenant" | "data_core" | "flow_type" | "result">;
|
|
519
|
+
replayIdleDuration: Histogram<"tenant" | "data_core" | "flow_type" | "reason">;
|
|
404
520
|
};
|
|
521
|
+
declare class ReplayStageObserver {
|
|
522
|
+
private readonly stageMetrics;
|
|
523
|
+
private readonly source;
|
|
524
|
+
private readonly now;
|
|
525
|
+
constructor(stageMetrics: DataPumpMetrics, source: ReplaySourceLabels, now?: () => number);
|
|
526
|
+
observeFetch<T extends {
|
|
527
|
+
events: unknown[];
|
|
528
|
+
}>(operation: () => Promise<T>): Promise<T>;
|
|
529
|
+
observeHandler<T>(events: unknown[], operation: () => Promise<T>): Promise<T>;
|
|
530
|
+
observeAcknowledgement<T>(operation: () => T): T;
|
|
531
|
+
observeCheckpoint<T>(operation: () => Promise<T> | T): Promise<T>;
|
|
532
|
+
observeIdle<T>(reason: ReplayIdleReason, operation: () => Promise<T>): Promise<T>;
|
|
533
|
+
private observeResult;
|
|
534
|
+
private elapsedSeconds;
|
|
535
|
+
}
|
|
405
536
|
declare const clusterMetrics: {
|
|
406
|
-
activeWorkersGauge:
|
|
407
|
-
leaderStatusGauge:
|
|
408
|
-
eventsDistributedCounter:
|
|
409
|
-
workerAcksCounter:
|
|
410
|
-
workerFailsCounter:
|
|
537
|
+
activeWorkersGauge: Gauge<string>;
|
|
538
|
+
leaderStatusGauge: Gauge<string>;
|
|
539
|
+
eventsDistributedCounter: Counter<string>;
|
|
540
|
+
workerAcksCounter: Counter<string>;
|
|
541
|
+
workerFailsCounter: Counter<string>;
|
|
411
542
|
};
|
|
412
543
|
|
|
413
544
|
declare class NatsConnectionManager {
|
|
@@ -514,4 +645,4 @@ declare class DeliveryTracker {
|
|
|
514
645
|
|
|
515
646
|
declare const noOpLogger: FlowcoreLogger;
|
|
516
647
|
|
|
517
|
-
export { DeliveryTracker, FlowcoreDataPump, type FlowcoreDataPumpAuth, FlowcoreDataPumpCluster, type FlowcoreDataPumpClusterOptions, type FlowcoreDataPumpCoordinator, type FlowcoreDataPumpDataSource, type FlowcoreDataPumpOptions, type FlowcoreDataPumpProcessor, type FlowcoreDataPumpState, type FlowcoreDataPumpStateManager, FlowcoreDataSource, type FlowcoreDataSourceOptions, type FlowcoreLogger, NatsConnectionManager, NatsDistributionLeader, type NatsDistributionReply, type NatsDistributionRequest, NatsDistributionWorker, type PendingDelivery, PulseEmitter, type PulseEmitterOptions, type PulseLogLevel, type PulseSnapshot, type WsAckMessage, WsConnection, type WsConnectionOptions, type WsEventsMessage, type WsFailMessage, type WsMessage, type WsPingMessage, type WsPongMessage, clusterMetrics, dataPumpPromRegistry, deserializeMessage, metrics, noOpLogger, serializeMessage };
|
|
648
|
+
export { type DataPumpMetrics, DeliveryTracker, FlowcoreDataPump, type FlowcoreDataPumpAuth, FlowcoreDataPumpCluster, type FlowcoreDataPumpClusterOptions, type FlowcoreDataPumpCoordinator, type FlowcoreDataPumpDataSource, type FlowcoreDataPumpOptions, type FlowcoreDataPumpProcessor, type FlowcoreDataPumpState, type FlowcoreDataPumpStateManager, FlowcoreDataSource, type FlowcoreDataSourceOptions, type FlowcoreLogger, NatsConnectionManager, NatsDistributionLeader, type NatsDistributionReply, type NatsDistributionRequest, NatsDistributionWorker, type PendingDelivery, PulseEmitter, type PulseEmitterOptions, type PulseLogLevel, type PulseSnapshot, REPLAY_BATCH_SIZE_BUCKETS, REPLAY_DURATION_BUCKETS_SECONDS, REPLAY_EVENT_COUNT_BUCKETS, REPLAY_FETCH_RESULTS, REPLAY_IDLE_REASONS, REPLAY_STAGE_RESULTS, type ReplayBatchSizeBucket, type ReplayIdleReason, type ReplaySourceLabels, ReplayStageObserver, type WsAckMessage, WsConnection, type WsConnectionOptions, type WsEventsMessage, type WsFailMessage, type WsMessage, type WsPingMessage, type WsPongMessage, clusterMetrics, createDataPumpMetrics, dataPumpPromRegistry, deserializeMessage, metrics, noOpLogger, replayBatchSizeBucket, serializeMessage };
|