@uns-kit/core 3.0.39 → 3.0.41
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/MIGRATIONS.md +44 -0
- package/README.md +8 -0
- package/dist/runtime/mqtt-drain.d.ts +7 -0
- package/dist/runtime/mqtt-drain.d.ts.map +1 -1
- package/dist/runtime/mqtt-drain.js +7 -0
- package/dist/runtime/mqtt-drain.js.map +1 -1
- package/dist/runtime/mqtt-handover-state.d.ts +10 -2
- package/dist/runtime/mqtt-handover-state.d.ts.map +1 -1
- package/dist/runtime/mqtt-handover-state.js +8 -1
- package/dist/runtime/mqtt-handover-state.js.map +1 -1
- package/dist/uns/uns-interfaces.d.ts +13 -1
- package/dist/uns/uns-interfaces.d.ts.map +1 -1
- package/dist/uns/uns-interfaces.js +12 -0
- package/dist/uns/uns-interfaces.js.map +1 -1
- package/dist/uns/uns-packet.d.ts.map +1 -1
- package/dist/uns/uns-packet.js +4 -9
- package/dist/uns/uns-packet.js.map +1 -1
- package/dist/uns/uns-proxy-process.d.ts +5 -1
- package/dist/uns/uns-proxy-process.d.ts.map +1 -1
- package/dist/uns/uns-proxy-process.js +38 -7
- package/dist/uns/uns-proxy-process.js.map +1 -1
- package/dist/uns-mqtt/mqtt-interfaces.d.ts +1 -0
- package/dist/uns-mqtt/mqtt-interfaces.d.ts.map +1 -1
- package/dist/uns-mqtt/mqtt-interfaces.js.map +1 -1
- package/dist/uns-mqtt/mqtt-proxy.d.ts +2 -0
- package/dist/uns-mqtt/mqtt-proxy.d.ts.map +1 -1
- package/dist/uns-mqtt/mqtt-proxy.js +9 -0
- package/dist/uns-mqtt/mqtt-proxy.js.map +1 -1
- package/dist/uns-mqtt/mqtt-worker.d.ts +1 -0
- package/dist/uns-mqtt/mqtt-worker.d.ts.map +1 -1
- package/dist/uns-mqtt/mqtt-worker.js +36 -3
- package/dist/uns-mqtt/mqtt-worker.js.map +1 -1
- package/dist/uns-mqtt/throttled-queue.d.ts +5 -1
- package/dist/uns-mqtt/throttled-queue.d.ts.map +1 -1
- package/dist/uns-mqtt/throttled-queue.js +33 -3
- package/dist/uns-mqtt/throttled-queue.js.map +1 -1
- package/dist/uns-mqtt/uns-mqtt-proxy.d.ts +11 -0
- package/dist/uns-mqtt/uns-mqtt-proxy.d.ts.map +1 -1
- package/dist/uns-mqtt/uns-mqtt-proxy.js +106 -8
- package/dist/uns-mqtt/uns-mqtt-proxy.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"throttled-queue.js","sourceRoot":"","sources":["../../src/uns-mqtt/throttled-queue.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { IClientPublishOptions } from \"mqtt\";\nimport { join } from \"path\";\n\nimport { basePath } from \"../base-path.js\";\nimport logger from \"../logger.js\";\nimport { inputCursorSchema, inputFingerprint, inputPreviewSchema, uniqueInputBoundary, type InputQueueCursor } from \"../runtime/input-queue-boundary.js\";\n\n/**\n * Abstract base class that encapsulates common functionality for managing\n * a throttled in‑memory queue with an optional disk persistence.\n */\nabstract class ThrottledQueue<T> {\n protected queue: T[] = [];\n protected lastProcessedItems: T[] = [];\n protected isProcessing = false;\n protected inFlight = 0;\n protected maxConcurrency: number;\n public delay: number;\n protected persistToDisk: boolean;\n protected persistenceFilePath: string;\n protected previousLoggedSize = 0;\n protected instanceName: string;\n protected active: boolean = true;\n private inactiveLogSent = false;\n\n constructor(delay: number, persistToDisk: boolean, instanceName: string, maxConcurrency: number = 1) {\n this.delay = delay;\n this.persistToDisk = persistToDisk;\n this.instanceName = instanceName;\n this.maxConcurrency = Math.max(1, maxConcurrency);\n\n if (this.persistToDisk) {\n this.loadQueueFromDisk();\n }\n }\n\n /**\n * Process the queue items one at a time with a delay between each.\n */\n protected async processQueue(): Promise<void> {\n if (this.isProcessing) return;\n\n if (!this.active) {\n if (!this.inactiveLogSent) {\n logger.info(`${this.instanceName} - Queue is not active. Exiting processQueue.`);\n this.inactiveLogSent = true;\n }\n this.isProcessing = false;\n return;\n }\n this.isProcessing = true;\n // Reset the flag when processing actually starts.\n this.inactiveLogSent = false;\n\n try {\n while (this.queue.length > 0 && this.inFlight < this.maxConcurrency) {\n // Check if the queue is active\n if (!this.active) {\n logger.info(`${this.instanceName} - Queue processing paused.`);\n return; // Exit the loop and stop processing\n }\n\n const item = this.queue.shift();\n if (!item) {\n continue;\n }\n\n this.inFlight += 1;\n void this.processItemWithBookkeeping(item);\n\n if (this.persistToDisk) {\n this.saveQueueToDisk();\n }\n\n this.logQueueSize();\n\n if (this.delay > 0 && this.queue.length > 0 && this.inFlight < this.maxConcurrency) {\n await new Promise((resolve) => setTimeout(resolve, this.delay));\n }\n }\n } finally {\n this.isProcessing = false;\n if (this.active && this.queue.length > 0 && this.inFlight < this.maxConcurrency) {\n void this.processQueue();\n }\n }\n }\n\n private async processItemWithBookkeeping(item: T): Promise<void> {\n try {\n await this.processItem(item);\n // Only store 10 last processed items\n if (this.lastProcessedItems.length >= 10) {\n this.lastProcessedItems.shift();\n }\n // Store the last processed item\n this.lastProcessedItems.push(item);\n } catch (error) {\n // Specific error handling can be done in the subclass if needed.\n logger.error(`${this.instanceName} - Error processing item: ${(error as Error).message}`);\n } finally {\n this.inFlight = Math.max(0, this.inFlight - 1);\n\n if (this.persistToDisk) {\n this.saveQueueToDisk();\n }\n\n this.logQueueSize();\n\n // Check if the queue is active\n if (this.active && this.queue.length > 0) {\n void this.processQueue();\n }\n }\n }\n\n /**\n * Log changes to the queue size at significant thresholds.\n */\n protected logQueueSize(): void {\n const className = `${this.constructor.name.includes(\"Publisher\") ? \"Publisher\" : this.constructor.name.includes(\"Subscriber\") ? \"Subscriber\" : \"Unknown\"}`;\n const pendingCount = this.getPendingCount();\n if (\n pendingCount > 1\n && pendingCount > this.previousLoggedSize\n && Math.floor(pendingCount / 100) > Math.floor(this.previousLoggedSize / 100)\n ) {\n logger.info(`${this.instanceName} - ${className} queue size length is ${pendingCount}.`);\n this.previousLoggedSize = pendingCount;\n } else if (pendingCount === 0 && this.previousLoggedSize > 0) {\n logger.info(`${this.instanceName} - ${className} queue is empty.`);\n this.previousLoggedSize = 0;\n }\n }\n\n protected getPendingCount(): number {\n return this.queue.length + this.inFlight;\n }\n\n /**\n * Save the current queue to disk.\n */\n protected saveQueueToDisk(): void {\n try {\n const queueData = this.queue.map((item) => this.serializeItem(item));\n const dir = join(this.persistenceFilePath, \"..\");\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(this.persistenceFilePath, JSON.stringify(queueData, null, 2));\n logger.debug(`${this.instanceName} - Queue saved to disk.`);\n } catch (error: any) {\n logger.error(`${this.instanceName} - Error saving queue to disk: ${error.message}`);\n }\n }\n\n /**\n * Load the queue from disk.\n */\n protected loadQueueFromDisk(): void {\n try {\n if (existsSync(this.persistenceFilePath)) {\n const queueData = JSON.parse(readFileSync(this.persistenceFilePath, \"utf8\"));\n this.queue = queueData.map((data: any) => this.deserializeItem(data));\n logger.info(`${this.instanceName} - Queue loaded from disk.`);\n }\n } catch (error: any) {\n logger.error(`${this.instanceName} - Error loading queue from disk: ${error.message}`);\n }\n }\n\n /**\n * Process a single queue item.\n */\n protected abstract processItem(item: T): Promise<void>;\n\n /**\n * Serialize a queue item for persistence.\n */\n protected abstract serializeItem(item: T): any;\n\n /**\n * Deserialize persisted data into a queue item.\n */\n protected abstract deserializeItem(data: any): T;\n}\n\n/**\n * Interface representing a queued publish item.\n */\ninterface PublisherQueueItem {\n topic: string;\n message: string;\n id: string;\n options?: IClientPublishOptions;\n resolve: () => void;\n reject: (err: any) => void;\n}\n\n/**\n * ThrottledPublisher: manages a queue of outgoing publish requests,\n * sending one message at a time using a provided publish function.\n */\nexport class ThrottledPublisher extends ThrottledQueue<PublisherQueueItem> {\n private publishFunction: (topic: string, message: string, id: string, options?: IClientPublishOptions) => Promise<void>;\n private maxPendingPublishes?: number;\n\n /**\n * @param delay Delay between messages in milliseconds.\n * @param publishFunction Function to perform the actual publish.\n * @param persistToDisk Whether to persist the queue to disk.\n * @param persistenceFilePath File path for queue persistence.\n * @param instanceName Unique instance name for logging.\n */\n constructor(\n delay: number,\n publishFunction: (topic: string, message: string, id: string, options?: IClientPublishOptions) => Promise<void>,\n persistToDisk: boolean = false,\n persistenceFilePath: string = join(basePath, \"/publisherQueue/\", \"throttled-publisher-queue.json\"),\n instanceName: string,\n active: boolean,\n maxConcurrency: number = 1,\n maxPendingPublishes?: number,\n ) {\n super(delay, persistToDisk, instanceName, maxConcurrency);\n this.persistenceFilePath = persistenceFilePath;\n this.publishFunction = publishFunction;\n this.active = active;\n this.maxPendingPublishes = maxPendingPublishes;\n if (active) {\n logger.info(`${this.instanceName} - Publisher is active.`);\n } else {\n logger.info(`${this.instanceName} - Publisher is passive.`);\n }\n }\n\n /**\n * Enqueue a publish request.\n */\n public enqueue(topic: string, message: string, id: string, options?: IClientPublishOptions): Promise<void> {\n try {\n this.assertCanAcceptPublish();\n return this.enqueueAcceptedPublish(topic, message, id, options);\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n /**\n * Enqueue a publish request and throw synchronously if the bounded queue is full.\n */\n public enqueueOrThrow(topic: string, message: string, id: string, options?: IClientPublishOptions): Promise<void> {\n this.assertCanAcceptPublish();\n return this.enqueueAcceptedPublish(topic, message, id, options);\n }\n\n private assertCanAcceptPublish(): void {\n if (this.maxPendingPublishes !== undefined && this.getPendingCount() >= this.maxPendingPublishes) {\n throw new Error(`${this.instanceName} - Publisher queue is full (${this.maxPendingPublishes}).`);\n }\n }\n\n private enqueueAcceptedPublish(topic: string, message: string, id: string, options?: IClientPublishOptions): Promise<void> {\n return new Promise((resolve, reject) => {\n this.queue.push({ topic, message, id, options, resolve, reject });\n\n // Trigger logging after a new message is added.\n this.logQueueSize(); \n\n if (this.persistToDisk) {\n this.saveQueueToDisk();\n }\n\n if (this.active) {\n this.processQueue();\n }\n });\n }\n\n private computeHashForBatch(messages: any[]): string {\n const data = JSON.stringify(messages);\n return createHash(\"sha256\").update(data).digest(\"hex\");\n }\n\n /**\n * Switch the publisher to a passive state and return a snapshot\n */\n public becomeActive(snapshot: { referenceHash: string; batchSize: number }): void {\n // If snapshot is empty (batchSize is zero), start processing from the beginning.\n if (snapshot.batchSize === 0 || snapshot.batchSize === undefined || snapshot.referenceHash === undefined) {\n this.active = true;\n logger.info(`${this.instanceName} - Publisher became active.`);\n this.processQueue();\n return;\n }\n\n const { referenceHash, batchSize } = snapshot;\n let resumeIndex = -1;\n\n // Use batchSize as the window length.\n for (let i = 0; i <= this.queue.length - batchSize; i++) {\n const currentBatch = this.queue.slice(i, i + batchSize);\n const currentHash = this.computeHashForBatch(currentBatch);\n if (currentHash === referenceHash) {\n resumeIndex = i + batchSize; // resume immediately after the matched batch\n break;\n }\n }\n\n if (resumeIndex !== -1) {\n // Adjust the queue so that processing resumes after the matching batch.\n this.queue = this.queue.slice(resumeIndex);\n logger.info(`${this.instanceName} - Publisher resumed from the matched snapshot position.`);\n } else if (this.queue.length > 0) {\n // Log info message and process the entire queue if no match is found.\n logger.info(`${this.instanceName} - No matching batch found during resume; processing the entire publisher's queue.`);\n }\n\n this.active = true;\n logger.info(`${this.instanceName} - Publisher became active.`);\n this.processQueue();\n }\n\n /**\n * Switch the publisher to a passive state and return a snapshot\n */\n public async becomePassive(n: number): Promise<{ referenceHash: string; batchSize: number; }> {\n this.active = false;\n logger.info(`${this.instanceName} - Publisher became passive.`);\n const batch = this.queue.slice(-n);\n const batchSize = batch.length;\n const referenceHash = this.computeHashForBatch(batch);\n if (batchSize > 0) {\n logger.info(`${this.instanceName} - Publisher batch reference hash: ${referenceHash}, size: ${batchSize}`);\n }\n return { referenceHash, batchSize };\n }\n\n public getState(): boolean {\n return this.active;\n }\n\n /**\n * Process a single publish request.\n */\n protected async processItem(item: PublisherQueueItem): Promise<void> {\n try {\n await this.publishFunction(item.topic, item.message, item.id, item.options);\n item.resolve();\n } catch (error) {\n item.reject(error);\n }\n }\n\n /**\n * Serialize a publish request for persistence.\n */\n protected serializeItem(item: PublisherQueueItem): any {\n return {\n topic: item.topic,\n message: item.message,\n id: item.id,\n options: item.options,\n };\n }\n\n /**\n * Deserialize persisted data into a publish request.\n */\n protected deserializeItem(data: any): PublisherQueueItem {\n return {\n topic: data.topic,\n message: data.message,\n id: data.id,\n options: data.options,\n resolve: () => {},\n reject: (err: any) => logger.error(`${this.instanceName} - Error processing queued publish item: ${err.message}`),\n };\n }\n}\n\n/**\n * Interface representing a queued subscribe item.\n */\ninterface SubscriberQueueItem {\n topic: string;\n message: string;\n timestamp: number;\n}\n\n/**\n * ThrottledSubscriber: manages a queue of incoming messages and processes\n * them one at a time using a provided message handler.\n */\nexport class ThrottledSubscriber extends ThrottledQueue<SubscriberQueueItem> {\n private messageHandler: (topic: string, message: string) => Promise<void>;\n\n /**\n * @param delay Delay between processing messages in milliseconds.\n * @param messageHandler Function to process incoming messages.\n * @param persistToDisk Whether to persist the queue to disk.\n * @param persistenceFilePath File path for queue persistence.\n * @param instanceName Unique instance name for logging.\n */\n constructor(\n delay: number,\n messageHandler: (topic: string, message: string) => Promise<void>,\n persistToDisk: boolean = false,\n persistenceFilePath: string = join(basePath, \"/subscriberQueue/\", \"throttled-subscriber-queue.json\"),\n instanceName: string,\n active: boolean,\n ) {\n super(delay, persistToDisk, instanceName);\n this.persistenceFilePath = persistenceFilePath;\n this.messageHandler = messageHandler;\n this.active = active;\n if (active) {\n logger.info(`${this.instanceName} - Subscriber is active.`);\n } else {\n logger.info(`${this.instanceName} - Subscriber is passive.`);\n }\n }\n\n /**\n * Enqueue subscribe messages for processing.\n */\n public enqueue(topic: string, message: string): void {\n this.queue.push({ topic, message, timestamp: Date.now() });\n \n // Trigger logging after a new message is added.\n this.logQueueSize();\n \n if (this.persistToDisk) {\n this.saveQueueToDisk();\n }\n\n if (this.active) {\n this.processQueue();\n }\n }\n\n /**\n * Process a single subscribe message.\n */\n protected async processItem(item: SubscriberQueueItem): Promise<void> {\n await this.messageHandler(item.topic, item.message);\n }\n\n /**\n * Serialize a subscribe message for persistence.\n */\n protected serializeItem(item: SubscriberQueueItem): any {\n return {\n message: item.message,\n };\n }\n\n /**\n * Deserialize persisted data into a subscribe message.\n */\n protected deserializeItem(data: any): SubscriberQueueItem {\n return {\n topic: data.topic,\n message: data.message,\n timestamp: data.timestamp,\n };\n }\n\n /**\n * Get the current state of the subscriber (active or passive).\n */\n public getState(): boolean {\n return this.active;\n }\n\n /**\n * Computes a SHA‑256 hash for a given batch of subscriber items.\n */\n private computeHashForBatch(messages: SubscriberQueueItem[], strict = false): string {\n const data = JSON.stringify(messages.map((item) => strict ? { topic: item.topic, message: item.message } : this.serializeItem(item)));\n return createHash(\"sha256\").update(data).digest(\"hex\");\n }\n\n /**\n * Switch the subscriber to a passive state and return a snapshot.\n */\n public async becomePassive(n: number, strict = false): Promise<InputQueueCursor> {\n this.active = false;\n logger.info(`${this.instanceName} - Subscriber is passive.`);\n while (this.inFlight > 0) await new Promise(resolve => setTimeout(resolve, 1));\n const batch = this.lastProcessedItems.slice(-n);\n const batchSize = batch.length;\n const referenceHash = this.computeHashForBatch(batch, strict);\n if (batchSize > 0) {\n logger.info(`${this.instanceName} - Subscriber batch reference hash: ${referenceHash}, size: ${batchSize}`);\n }\n return { referenceHash, batchSize, ...(strict ? { processedTail: this.lastProcessedItems.map(inputFingerprint) } : {}) };\n }\n\n /**\n * Switch the subscriber to an active state and resume processing.\n */\n private preparedResume: number | undefined;\n\n public getInputPreview(): string[] {\n if (this.active) throw Error(\"MQTT successor is not passive\");\n return this.queue.slice(-100).map(inputFingerprint);\n }\n\n public canResumeInput(preview: unknown): boolean {\n const parsed = inputPreviewSchema.safeParse(preview);\n if (!this.active || !parsed.success) return false;\n try { uniqueInputBoundary(this.lastProcessedItems.map(inputFingerprint), parsed.data); return true; }\n catch { return false; }\n }\n\n /** Validate a unique overlap without consuming input or activating this owner. */\n public prepareResume(snapshot: InputQueueCursor): void {\n if (this.active) throw Error(\"MQTT successor is not passive\");\n this.preparedResume = undefined;\n snapshot = inputCursorSchema.parse(snapshot);\n if (snapshot.processedTail) {\n this.preparedResume = uniqueInputBoundary(snapshot.processedTail, this.queue.map(inputFingerprint));\n return;\n }\n if (snapshot.batchSize === 0) { this.preparedResume = 0; return; }\n const matches: number[] = [];\n for (let i = 0; i <= this.queue.length - snapshot.batchSize; i++) {\n if (this.computeHashForBatch(this.queue.slice(i, i + snapshot.batchSize), true) === snapshot.referenceHash)\n matches.push(i + snapshot.batchSize);\n }\n if (matches.length !== 1) throw Error(\"MQTT input overlap is missing or ambiguous; successor stays passive\");\n this.preparedResume = matches[0];\n }\n\n public activatePreparedResume(): void {\n if (this.active || this.preparedResume === undefined) throw Error(\"MQTT resume was not prepared\");\n this.queue = this.queue.slice(this.preparedResume);\n this.preparedResume = undefined;\n this.active = true;\n void this.processQueue();\n }\n\n public becomeActive(snapshot: { referenceHash: string; batchSize: number }): void {\n // If snapshot is empty (batchSize is zero), start processing from the beginning.\n if (snapshot.batchSize === 0 || snapshot.batchSize === undefined || snapshot.referenceHash === undefined) {\n this.active = true;\n logger.info(`${this.instanceName} - Subscriber became active.`); \n this.processQueue();\n return;\n }\n\n const { referenceHash, batchSize } = snapshot;\n let resumeIndex = -1;\n\n // Use batchSize as the window length.\n for (let i = 0; i <= this.queue.length - batchSize; i++) {\n const currentBatch = this.queue.slice(i, i + batchSize);\n const currentHash = this.computeHashForBatch(currentBatch);\n if (currentHash === referenceHash) {\n resumeIndex = i + batchSize; // resume immediately after the matched batch\n break;\n }\n }\n\n if (resumeIndex !== -1) {\n // Adjust the queue so that processing resumes after the matching batch.\n const queueSlice = this.queue.slice(resumeIndex); \n this.queue = queueSlice;\n logger.info(`${this.instanceName} - Subscriber resumed from the matched snapshot position.`);\n } else if (this.queue.length > 0) {\n // Log info message and process the entire queue if no match is found.\n logger.info(`${this.instanceName} - No matching batch found during resume; processing the entire subscriber's queue.`);\n }\n\n this.active = true;\n logger.info(`${this.instanceName} - Subscriber became active.`); \n this.processQueue();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"throttled-queue.js","sourceRoot":"","sources":["../../src/uns-mqtt/throttled-queue.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { IClientPublishOptions } from \"mqtt\";\nimport { join } from \"path\";\n\nimport { basePath } from \"../base-path.js\";\nimport logger from \"../logger.js\";\nimport { inputCursorSchema, inputFingerprint, inputPreviewSchema, uniqueInputBoundary, type InputQueueCursor } from \"../runtime/input-queue-boundary.js\";\n\n/**\n * Abstract base class that encapsulates common functionality for managing\n * a throttled in‑memory queue with an optional disk persistence.\n */\nabstract class ThrottledQueue<T> {\n protected queue: T[] = [];\n protected lastProcessedItems: T[] = [];\n protected isProcessing = false;\n protected inFlight = 0;\n protected maxConcurrency: number;\n public delay: number;\n protected persistToDisk: boolean;\n protected persistenceFilePath: string;\n protected previousLoggedSize = 0;\n protected instanceName: string;\n protected active: boolean = true;\n private inactiveLogSent = false;\n\n constructor(delay: number, persistToDisk: boolean, instanceName: string, maxConcurrency: number = 1) {\n this.delay = delay;\n this.persistToDisk = persistToDisk;\n this.instanceName = instanceName;\n this.maxConcurrency = Math.max(1, maxConcurrency);\n\n if (this.persistToDisk) {\n this.loadQueueFromDisk();\n }\n }\n\n /**\n * Process the queue items one at a time with a delay between each.\n */\n protected async processQueue(): Promise<void> {\n if (this.isProcessing) return;\n\n if (!this.active) {\n if (!this.inactiveLogSent) {\n logger.info(`${this.instanceName} - Queue is not active. Exiting processQueue.`);\n this.inactiveLogSent = true;\n }\n this.isProcessing = false;\n return;\n }\n this.isProcessing = true;\n // Reset the flag when processing actually starts.\n this.inactiveLogSent = false;\n\n try {\n while (this.queue.length > 0 && this.inFlight < this.maxConcurrency) {\n // Check if the queue is active\n if (!this.active) {\n logger.info(`${this.instanceName} - Queue processing paused.`);\n return; // Exit the loop and stop processing\n }\n\n const item = this.queue.shift();\n if (!item) {\n continue;\n }\n\n this.inFlight += 1;\n void this.processItemWithBookkeeping(item);\n\n if (this.persistToDisk) {\n this.saveQueueToDisk();\n }\n\n this.logQueueSize();\n\n if (this.delay > 0 && this.queue.length > 0 && this.inFlight < this.maxConcurrency) {\n await new Promise((resolve) => setTimeout(resolve, this.delay));\n }\n }\n } finally {\n this.isProcessing = false;\n if (this.active && this.queue.length > 0 && this.inFlight < this.maxConcurrency) {\n void this.processQueue();\n }\n }\n }\n\n private async processItemWithBookkeeping(item: T): Promise<void> {\n try {\n await this.processItem(item);\n // Only store 10 last processed items\n if (this.lastProcessedItems.length >= 10) {\n this.lastProcessedItems.shift();\n }\n // Store the last processed item\n this.lastProcessedItems.push(item);\n } catch (error) {\n // Specific error handling can be done in the subclass if needed.\n logger.error(`${this.instanceName} - Error processing item: ${(error as Error).message}`);\n } finally {\n this.inFlight = Math.max(0, this.inFlight - 1);\n\n if (this.persistToDisk) {\n this.saveQueueToDisk();\n }\n\n this.logQueueSize();\n\n // Check if the queue is active\n if (this.active && this.queue.length > 0) {\n void this.processQueue();\n }\n }\n }\n\n /**\n * Log changes to the queue size at significant thresholds.\n */\n protected logQueueSize(): void {\n const className = `${this.constructor.name.includes(\"Publisher\") ? \"Publisher\" : this.constructor.name.includes(\"Subscriber\") ? \"Subscriber\" : \"Unknown\"}`;\n const pendingCount = this.getPendingCount();\n if (\n pendingCount > 1\n && pendingCount > this.previousLoggedSize\n && Math.floor(pendingCount / 100) > Math.floor(this.previousLoggedSize / 100)\n ) {\n logger.info(`${this.instanceName} - ${className} queue size length is ${pendingCount}.`);\n this.previousLoggedSize = pendingCount;\n } else if (pendingCount === 0 && this.previousLoggedSize > 0) {\n logger.info(`${this.instanceName} - ${className} queue is empty.`);\n this.previousLoggedSize = 0;\n }\n }\n\n protected getPendingCount(): number {\n return this.queue.length + this.inFlight;\n }\n\n /**\n * Save the current queue to disk.\n */\n protected saveQueueToDisk(): void {\n try {\n const queueData = this.queue.map((item) => this.serializeItem(item));\n const dir = join(this.persistenceFilePath, \"..\");\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(this.persistenceFilePath, JSON.stringify(queueData, null, 2));\n logger.debug(`${this.instanceName} - Queue saved to disk.`);\n } catch (error: any) {\n logger.error(`${this.instanceName} - Error saving queue to disk: ${error.message}`);\n }\n }\n\n /**\n * Load the queue from disk.\n */\n protected loadQueueFromDisk(): void {\n try {\n if (existsSync(this.persistenceFilePath)) {\n const queueData = JSON.parse(readFileSync(this.persistenceFilePath, \"utf8\"));\n this.queue = queueData.map((data: any) => this.deserializeItem(data));\n logger.info(`${this.instanceName} - Queue loaded from disk.`);\n }\n } catch (error: any) {\n logger.error(`${this.instanceName} - Error loading queue from disk: ${error.message}`);\n }\n }\n\n /**\n * Process a single queue item.\n */\n protected abstract processItem(item: T): Promise<void>;\n\n /**\n * Serialize a queue item for persistence.\n */\n protected abstract serializeItem(item: T): any;\n\n /**\n * Deserialize persisted data into a queue item.\n */\n protected abstract deserializeItem(data: any): T;\n}\n\n/**\n * Interface representing a queued publish item.\n */\ninterface PublisherQueueItem {\n topic: string;\n message: string;\n id: string;\n options?: IClientPublishOptions;\n resolve: () => void;\n reject: (err: any) => void;\n}\n\n/**\n * ThrottledPublisher: manages a queue of outgoing publish requests,\n * sending one message at a time using a provided publish function.\n */\nexport class ThrottledPublisher extends ThrottledQueue<PublisherQueueItem> {\n private publishFunction: (topic: string, message: string, id: string, options?: IClientPublishOptions) => Promise<void>;\n private maxPendingPublishes?: number;\n\n /**\n * @param delay Delay between messages in milliseconds.\n * @param publishFunction Function to perform the actual publish.\n * @param persistToDisk Whether to persist the queue to disk.\n * @param persistenceFilePath File path for queue persistence.\n * @param instanceName Unique instance name for logging.\n */\n constructor(\n delay: number,\n publishFunction: (topic: string, message: string, id: string, options?: IClientPublishOptions) => Promise<void>,\n persistToDisk: boolean = false,\n persistenceFilePath: string = join(basePath, \"/publisherQueue/\", \"throttled-publisher-queue.json\"),\n instanceName: string,\n active: boolean,\n maxConcurrency: number = 1,\n maxPendingPublishes?: number,\n ) {\n super(delay, persistToDisk, instanceName, maxConcurrency);\n this.persistenceFilePath = persistenceFilePath;\n this.publishFunction = publishFunction;\n this.active = active;\n this.maxPendingPublishes = maxPendingPublishes;\n if (active) {\n logger.info(`${this.instanceName} - Publisher is active.`);\n } else {\n logger.info(`${this.instanceName} - Publisher is passive.`);\n }\n }\n\n /**\n * Enqueue a publish request.\n */\n public enqueue(topic: string, message: string, id: string, options?: IClientPublishOptions): Promise<void> {\n try {\n this.assertCanAcceptPublish();\n return this.enqueueAcceptedPublish(topic, message, id, options);\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n /**\n * Enqueue a publish request and throw synchronously if the bounded queue is full.\n */\n public enqueueOrThrow(topic: string, message: string, id: string, options?: IClientPublishOptions): Promise<void> {\n this.assertCanAcceptPublish();\n return this.enqueueAcceptedPublish(topic, message, id, options);\n }\n\n private assertCanAcceptPublish(): void {\n if (this.maxPendingPublishes !== undefined && this.getPendingCount() >= this.maxPendingPublishes) {\n throw new Error(`${this.instanceName} - Publisher queue is full (${this.maxPendingPublishes}).`);\n }\n }\n\n private enqueueAcceptedPublish(topic: string, message: string, id: string, options?: IClientPublishOptions): Promise<void> {\n return new Promise((resolve, reject) => {\n this.queue.push({ topic, message, id, options, resolve, reject });\n\n // Trigger logging after a new message is added.\n this.logQueueSize(); \n\n if (this.persistToDisk) {\n this.saveQueueToDisk();\n }\n\n if (this.active) {\n this.processQueue();\n }\n });\n }\n\n private computeHashForBatch(messages: any[]): string {\n const data = JSON.stringify(messages);\n return createHash(\"sha256\").update(data).digest(\"hex\");\n }\n\n /**\n * Switch the publisher to a passive state and return a snapshot\n */\n public becomeActive(snapshot: { referenceHash: string; batchSize: number }): void {\n // If snapshot is empty (batchSize is zero), start processing from the beginning.\n if (snapshot.batchSize === 0 || snapshot.batchSize === undefined || snapshot.referenceHash === undefined) {\n this.active = true;\n logger.info(`${this.instanceName} - Publisher became active.`);\n this.processQueue();\n return;\n }\n\n const { referenceHash, batchSize } = snapshot;\n let resumeIndex = -1;\n\n // Use batchSize as the window length.\n for (let i = 0; i <= this.queue.length - batchSize; i++) {\n const currentBatch = this.queue.slice(i, i + batchSize);\n const currentHash = this.computeHashForBatch(currentBatch);\n if (currentHash === referenceHash) {\n resumeIndex = i + batchSize; // resume immediately after the matched batch\n break;\n }\n }\n\n if (resumeIndex !== -1) {\n // Adjust the queue so that processing resumes after the matching batch.\n this.queue = this.queue.slice(resumeIndex);\n logger.info(`${this.instanceName} - Publisher resumed from the matched snapshot position.`);\n } else if (this.queue.length > 0) {\n // Log info message and process the entire queue if no match is found.\n logger.info(`${this.instanceName} - No matching batch found during resume; processing the entire publisher's queue.`);\n }\n\n this.active = true;\n logger.info(`${this.instanceName} - Publisher became active.`);\n this.processQueue();\n }\n\n /**\n * Switch the publisher to a passive state and return a snapshot\n */\n public async becomePassive(n: number): Promise<{ referenceHash: string; batchSize: number; }> {\n this.active = false;\n logger.info(`${this.instanceName} - Publisher became passive.`);\n const batch = this.queue.slice(-n);\n const batchSize = batch.length;\n const referenceHash = this.computeHashForBatch(batch);\n if (batchSize > 0) {\n logger.info(`${this.instanceName} - Publisher batch reference hash: ${referenceHash}, size: ${batchSize}`);\n }\n return { referenceHash, batchSize };\n }\n\n public getState(): boolean {\n return this.active;\n }\n\n /**\n * Process a single publish request.\n */\n protected async processItem(item: PublisherQueueItem): Promise<void> {\n try {\n await this.publishFunction(item.topic, item.message, item.id, item.options);\n item.resolve();\n } catch (error) {\n item.reject(error);\n }\n }\n\n /**\n * Serialize a publish request for persistence.\n */\n protected serializeItem(item: PublisherQueueItem): any {\n return {\n topic: item.topic,\n message: item.message,\n id: item.id,\n options: item.options,\n };\n }\n\n /**\n * Deserialize persisted data into a publish request.\n */\n protected deserializeItem(data: any): PublisherQueueItem {\n return {\n topic: data.topic,\n message: data.message,\n id: data.id,\n options: data.options,\n resolve: () => {},\n reject: (err: any) => logger.error(`${this.instanceName} - Error processing queued publish item: ${err.message}`),\n };\n }\n}\n\n/**\n * Interface representing a queued subscribe item.\n */\ninterface SubscriberQueueItem {\n topic: string;\n message: string;\n timestamp: number;\n}\n\n/**\n * ThrottledSubscriber: manages a queue of incoming messages and processes\n * them one at a time using a provided message handler.\n */\nexport class ThrottledSubscriber extends ThrottledQueue<SubscriberQueueItem> {\n private messageHandler: (topic: string, message: string) => Promise<void>;\n private inputFailed = false;\n\n /**\n * @param delay Delay between processing messages in milliseconds.\n * @param messageHandler Function to process incoming messages.\n * @param persistToDisk Whether to persist the queue to disk.\n * @param persistenceFilePath File path for queue persistence.\n * @param instanceName Unique instance name for logging.\n */\n constructor(\n delay: number,\n messageHandler: (topic: string, message: string) => Promise<void>,\n persistToDisk: boolean = false,\n persistenceFilePath: string = join(basePath, \"/subscriberQueue/\", \"throttled-subscriber-queue.json\"),\n instanceName: string,\n active: boolean,\n private readonly retainFailedInput = false,\n ) {\n super(delay, persistToDisk, instanceName);\n this.persistenceFilePath = persistenceFilePath;\n this.messageHandler = messageHandler;\n this.active = active;\n if (active) {\n logger.info(`${this.instanceName} - Subscriber is active.`);\n } else {\n logger.info(`${this.instanceName} - Subscriber is passive.`);\n }\n }\n\n /**\n * Enqueue subscribe messages for processing.\n */\n public enqueue(topic: string, message: string): void {\n this.queue.push({ topic, message, timestamp: Date.now() });\n \n // Trigger logging after a new message is added.\n this.logQueueSize();\n \n if (this.persistToDisk) {\n this.saveQueueToDisk();\n }\n\n if (this.active) {\n this.processQueue();\n }\n }\n\n /**\n * Process a single subscribe message.\n */\n protected async processItem(item: SubscriberQueueItem): Promise<void> {\n try {\n await this.messageHandler(item.topic, item.message);\n } catch (error) {\n if (this.retainFailedInput) {\n this.active = false;\n this.inputFailed = true;\n this.queue.unshift(item);\n }\n throw error;\n }\n }\n\n /**\n * Serialize a subscribe message for persistence.\n */\n protected serializeItem(item: SubscriberQueueItem): any {\n return {\n message: item.message,\n };\n }\n\n /**\n * Deserialize persisted data into a subscribe message.\n */\n protected deserializeItem(data: any): SubscriberQueueItem {\n return {\n topic: data.topic,\n message: data.message,\n timestamp: data.timestamp,\n };\n }\n\n /**\n * Get the current state of the subscriber (active or passive).\n */\n public getState(): boolean {\n return this.active;\n }\n\n /**\n * Computes a SHA‑256 hash for a given batch of subscriber items.\n */\n private computeHashForBatch(messages: SubscriberQueueItem[], strict = false): string {\n const data = JSON.stringify(messages.map((item) => strict ? { topic: item.topic, message: item.message } : this.serializeItem(item)));\n return createHash(\"sha256\").update(data).digest(\"hex\");\n }\n\n /**\n * Switch the subscriber to a passive state and return a snapshot.\n */\n public async becomePassive(n: number, strict = false): Promise<InputQueueCursor> {\n this.active = false;\n logger.info(`${this.instanceName} - Subscriber is passive.`);\n while (this.inFlight > 0) await new Promise(resolve => setTimeout(resolve, 1));\n const batch = this.lastProcessedItems.slice(-n);\n const batchSize = batch.length;\n const referenceHash = this.computeHashForBatch(batch, strict);\n if (batchSize > 0) {\n logger.info(`${this.instanceName} - Subscriber batch reference hash: ${referenceHash}, size: ${batchSize}`);\n }\n return { referenceHash, batchSize, ...(strict ? { processedTail: this.lastProcessedItems.map(inputFingerprint) } : {}) };\n }\n\n /** Drain owned input only; a passive shadow must never be activated by Stop. */\n public async drainOwnedInput(): Promise<void> {\n while (this.active && (this.queue.length || this.inFlight)) {\n if (this.inputFailed) throw Error(\"Managed MQTT input failed; retained input requires review\");\n await new Promise(resolve => setTimeout(resolve, 1));\n }\n if (this.inputFailed) throw Error(\"Managed MQTT input failed; retained input requires review\");\n await this.becomePassive(3, true);\n }\n\n /**\n * Switch the subscriber to an active state and resume processing.\n */\n private preparedResume: number | undefined;\n\n public getInputPreview(): string[] {\n if (this.inputFailed) throw Error(\"Managed MQTT input outcome requires review\");\n if (this.active) throw Error(\"MQTT successor is not passive\");\n return this.queue.slice(-100).map(inputFingerprint);\n }\n\n public canResumeInput(preview: unknown): boolean {\n const parsed = inputPreviewSchema.safeParse(preview);\n if (this.inputFailed || !this.active || !parsed.success) return false;\n try { uniqueInputBoundary(this.lastProcessedItems.map(inputFingerprint), parsed.data); return true; }\n catch { return false; }\n }\n\n /** Validate a unique overlap without consuming input or activating this owner. */\n public prepareResume(snapshot: InputQueueCursor): void {\n if (this.inputFailed) throw Error(\"Managed MQTT input outcome requires review\");\n if (this.active) throw Error(\"MQTT successor is not passive\");\n this.preparedResume = undefined;\n snapshot = inputCursorSchema.parse(snapshot);\n if (snapshot.processedTail) {\n this.preparedResume = uniqueInputBoundary(snapshot.processedTail, this.queue.map(inputFingerprint));\n return;\n }\n if (snapshot.batchSize === 0) { this.preparedResume = 0; return; }\n const matches: number[] = [];\n for (let i = 0; i <= this.queue.length - snapshot.batchSize; i++) {\n if (this.computeHashForBatch(this.queue.slice(i, i + snapshot.batchSize), true) === snapshot.referenceHash)\n matches.push(i + snapshot.batchSize);\n }\n if (matches.length !== 1) throw Error(\"MQTT input overlap is missing or ambiguous; successor stays passive\");\n this.preparedResume = matches[0];\n }\n\n public activatePreparedResume(): void {\n if (this.active || this.preparedResume === undefined) throw Error(\"MQTT resume was not prepared\");\n this.queue = this.queue.slice(this.preparedResume);\n this.preparedResume = undefined;\n this.active = true;\n void this.processQueue();\n }\n\n public becomeActive(snapshot: { referenceHash: string; batchSize: number }): void {\n if (this.inputFailed) throw Error(\"Managed MQTT input cannot be retried after an unknown application outcome\");\n // If snapshot is empty (batchSize is zero), start processing from the beginning.\n if (snapshot.batchSize === 0 || snapshot.batchSize === undefined || snapshot.referenceHash === undefined) {\n this.active = true;\n logger.info(`${this.instanceName} - Subscriber became active.`); \n this.processQueue();\n return;\n }\n\n const { referenceHash, batchSize } = snapshot;\n let resumeIndex = -1;\n\n // Use batchSize as the window length.\n for (let i = 0; i <= this.queue.length - batchSize; i++) {\n const currentBatch = this.queue.slice(i, i + batchSize);\n const currentHash = this.computeHashForBatch(currentBatch);\n if (currentHash === referenceHash) {\n resumeIndex = i + batchSize; // resume immediately after the matched batch\n break;\n }\n }\n\n if (resumeIndex !== -1) {\n // Adjust the queue so that processing resumes after the matching batch.\n const queueSlice = this.queue.slice(resumeIndex); \n this.queue = queueSlice;\n logger.info(`${this.instanceName} - Subscriber resumed from the matched snapshot position.`);\n } else if (this.queue.length > 0) {\n // Log info message and process the entire queue if no match is found.\n logger.info(`${this.instanceName} - No matching batch found during resume; processing the entire subscriber's queue.`);\n }\n\n this.active = true;\n logger.info(`${this.instanceName} - Subscriber became active.`); \n this.processQueue();\n }\n}\n"]}
|
|
@@ -49,6 +49,11 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
49
49
|
private publishesSealed;
|
|
50
50
|
private admissionBytes;
|
|
51
51
|
private pendingAdmissionBytes;
|
|
52
|
+
private capacityWaiters;
|
|
53
|
+
private capacityReservations;
|
|
54
|
+
private inputHandler?;
|
|
55
|
+
private pendingManagedInput?;
|
|
56
|
+
private managedInputFailure?;
|
|
52
57
|
private queueRequests;
|
|
53
58
|
constructor(mqttHost: string, processName: string, instanceName: string, unsParameters?: IUnsParameters, publisherActive?: boolean, subscriberActive?: boolean);
|
|
54
59
|
/**
|
|
@@ -73,6 +78,10 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
73
78
|
* @returns A promise that resolves when the message is accepted into the worker queue.
|
|
74
79
|
*/
|
|
75
80
|
private enqueueMessageToWorkerQueue;
|
|
81
|
+
private assertAdmissionOpen;
|
|
82
|
+
/** Register before enableMigrationDrain. Legacy event listeners are unchanged. */
|
|
83
|
+
setInputHandler(handler: (event: UnsEvents["input"]) => Promise<void>): void;
|
|
84
|
+
private handleManagedInput;
|
|
76
85
|
/**
|
|
77
86
|
* Sets the publisher active state.
|
|
78
87
|
*
|
|
@@ -119,6 +128,8 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
119
128
|
* until the queue is empty (all messages are processed).
|
|
120
129
|
*/
|
|
121
130
|
setSubscriberPassiveAndDrainQueue(strict?: boolean): Promise<UnsEvents["mqttWorker"]>;
|
|
131
|
+
/** Ordinary stop drains received owned input; live handover keeps its cutover cursor. */
|
|
132
|
+
drainInputForStop(): Promise<void>;
|
|
122
133
|
drainPublishes(timeoutMs?: number): Promise<void>;
|
|
123
134
|
flush(timeoutMs?: number): Promise<void>;
|
|
124
135
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uns-mqtt-proxy.d.ts","sourceRoot":"","sources":["../../src/uns-mqtt/uns-mqtt-proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4D,KAAK,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAC1I,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AAG/F,OAAO,EAAoD,KAAK,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAE5H,OAAO,EAAE,qBAAqB,EAAE,MAAM,MAAM,CAAC;AAM7C,OAAO,EAAE,mBAAmB,EAAsC,UAAU,EAAE,cAAc,EAAmG,SAAS,EAAa,MAAM,0BAA0B,CAAC;AAOtP,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAa3C,oBAAY,WAAW;IACrB,GAAG,QAAQ,CAAM,iCAAiC;IAClD;;;OAGG;IACH,KAAK,UAAU,CAAE,8BAA8B;IAC/C;;;OAGG;IACH,IAAI,SAAS;CACd;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAwCD,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,QAAQ;IAChD,gBAAuB,wBAAwB,SAAU;IACzD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IACxD,OAAO,CAAC,UAAU,
|
|
1
|
+
{"version":3,"file":"uns-mqtt-proxy.d.ts","sourceRoot":"","sources":["../../src/uns-mqtt/uns-mqtt-proxy.ts"],"names":[],"mappings":"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"}
|
|
@@ -56,12 +56,17 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
56
56
|
/** Current worker transport connection; does not imply an archive/database commit. */
|
|
57
57
|
getConnectionReadiness() { return this.lifecycleState === "running" && this.connectionReady; }
|
|
58
58
|
/** Latest broker SUBACK evidence; false before startup, disconnect or worker failure. */
|
|
59
|
-
getInputReadiness() { return this.lifecycleState === "running" && this.subscriptionsReady; }
|
|
59
|
+
getInputReadiness() { return this.lifecycleState === "running" && this.subscriptionsReady && !this.managedInputFailure; }
|
|
60
60
|
expectedWorkerExit = false;
|
|
61
61
|
publishQueueStatus;
|
|
62
62
|
publishesSealed = false;
|
|
63
63
|
admissionBytes = new Map();
|
|
64
64
|
pendingAdmissionBytes = 0;
|
|
65
|
+
capacityWaiters = [];
|
|
66
|
+
capacityReservations = 0;
|
|
67
|
+
inputHandler;
|
|
68
|
+
pendingManagedInput;
|
|
69
|
+
managedInputFailure;
|
|
65
70
|
queueRequests = new Map();
|
|
66
71
|
constructor(mqttHost, processName, instanceName, unsParameters, publisherActive = false, subscriberActive = false) {
|
|
67
72
|
super();
|
|
@@ -72,6 +77,8 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
72
77
|
// Bind state to semantic revision and actual endpoints/subscriptions, never credentials or client IDs.
|
|
73
78
|
this.stateCompatibility = contract ? createHash("sha256").update(JSON.stringify({
|
|
74
79
|
stateFormat: MQTT_HANDOVER_STATE_FORMAT, contract, host: mqttHost, ssl: unsParameters?.mqttSSL ?? false,
|
|
80
|
+
...(unsParameters?.managedInput ? { managedInput: true } : {}),
|
|
81
|
+
...(unsParameters?.allowNullData ? { explicitNullData: 1 } : {}),
|
|
75
82
|
port: unsParameters?.port ?? null, protocol: unsParameters?.protocol ?? null,
|
|
76
83
|
hosts: unsParameters?.hosts ?? [], servers: unsParameters?.servers ?? [],
|
|
77
84
|
subscriptions: [unsParameters?.mqttSubToTopics ?? []].flat().slice().sort(),
|
|
@@ -110,6 +117,14 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
110
117
|
servername: unsParameters?.servername,
|
|
111
118
|
};
|
|
112
119
|
this.unsParameters = { ...(unsParameters ?? {}) };
|
|
120
|
+
if (unsParameters?.publishBackpressure) {
|
|
121
|
+
const max = unsParameters.maxPendingPublishes;
|
|
122
|
+
const waiting = unsParameters.publishBackpressure.maxWaiting ?? 32;
|
|
123
|
+
if (!Number.isInteger(max) || max < 1 || !Number.isInteger(waiting) || waiting < 1 || waiting > 1024)
|
|
124
|
+
throw Error("Publish backpressure requires a positive bounded publish limit and 1..1024 waiters");
|
|
125
|
+
if (unsParameters.publishQueue?.enabled !== false && unsParameters.publishQueue)
|
|
126
|
+
throw Error("RAM admission backpressure cannot replace persistent outbox capacity policy");
|
|
127
|
+
}
|
|
113
128
|
if (unsParameters?.publishQueue) {
|
|
114
129
|
const queue = mqttPublishQueueSchema.parse(unsParameters.publishQueue);
|
|
115
130
|
if (queue.enabled === false) {
|
|
@@ -170,6 +185,7 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
170
185
|
publishThrottlingDelay: this.unsParameters.publishThrottlingDelay ?? 1,
|
|
171
186
|
publishConcurrency: this.unsParameters.publishConcurrency ?? 1,
|
|
172
187
|
maxPendingPublishes: this.unsParameters.maxPendingPublishes,
|
|
188
|
+
managedInput: this.unsParameters.managedInput,
|
|
173
189
|
subscribeThrottlingDelay: this.unsParameters.subscribeThrottlingDelay ?? 1,
|
|
174
190
|
persistToDisk: false,
|
|
175
191
|
publishQueue: this.unsParameters.publishQueue,
|
|
@@ -234,7 +250,15 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
234
250
|
this.notifyDrainWaiters();
|
|
235
251
|
}
|
|
236
252
|
else if (msg && msg.command === "input") {
|
|
237
|
-
|
|
253
|
+
const event = { topic: msg.topic, message: msg.message.toString(), packet: msg.packet };
|
|
254
|
+
if (this.unsParameters.managedInput) {
|
|
255
|
+
if (!this.inputHandler && typeof msg.id === "string")
|
|
256
|
+
this.pendingManagedInput = { id: msg.id, event };
|
|
257
|
+
else
|
|
258
|
+
void this.handleManagedInput(msg.id, event);
|
|
259
|
+
}
|
|
260
|
+
else
|
|
261
|
+
this.event.emit("input", event);
|
|
238
262
|
}
|
|
239
263
|
else if (msg && (msg.command === "handover_subscriber" || msg.command === "handover_publisher")) {
|
|
240
264
|
this.event.emit("mqttWorker", { command: msg.command, batchSize: msg.batchSize, referenceHash: msg.referenceHash, ...(msg.processedTail ? { processedTail: msg.processedTail } : {}), instanceName: this.instanceName });
|
|
@@ -277,6 +301,19 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
277
301
|
* @returns A promise that resolves when the message is accepted into the worker queue.
|
|
278
302
|
*/
|
|
279
303
|
async enqueueMessageToWorkerQueue(topic, message, options) {
|
|
304
|
+
if (this.unsParameters.publishBackpressure) {
|
|
305
|
+
this.assertAdmissionOpen();
|
|
306
|
+
const max = this.unsParameters.maxPendingPublishes;
|
|
307
|
+
if (this.capacityWaiters.length || this.pendingEnqueues.size + this.pendingPublishCompletions.size + this.capacityReservations >= max) {
|
|
308
|
+
if (this.capacityWaiters.length >= (this.unsParameters.publishBackpressure.maxWaiting ?? 32))
|
|
309
|
+
throw Error("MQTT output backpressure waiter limit reached; publication was not admitted");
|
|
310
|
+
await new Promise((resolve, reject) => {
|
|
311
|
+
this.capacityWaiters.push({ resolve, reject });
|
|
312
|
+
this.notifyDrainWaiters();
|
|
313
|
+
});
|
|
314
|
+
this.capacityReservations--;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
280
317
|
return new Promise((resolve, reject) => {
|
|
281
318
|
if (this.publishesSealed) {
|
|
282
319
|
reject(Error("MQTT output admission is sealed after clean migration drain"));
|
|
@@ -320,6 +357,37 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
320
357
|
this.notifyDrainWaiters();
|
|
321
358
|
});
|
|
322
359
|
}
|
|
360
|
+
assertAdmissionOpen() {
|
|
361
|
+
if (this.publishesSealed || this.lifecycleState !== "running")
|
|
362
|
+
throw Error("MQTT output admission is closed");
|
|
363
|
+
if (this.workerFailure)
|
|
364
|
+
throw this.workerFailure;
|
|
365
|
+
}
|
|
366
|
+
/** Register before enableMigrationDrain. Legacy event listeners are unchanged. */
|
|
367
|
+
setInputHandler(handler) {
|
|
368
|
+
if (!this.unsParameters.managedInput || this.inputHandler)
|
|
369
|
+
throw Error("Managed MQTT input requires one explicitly declared handler");
|
|
370
|
+
this.inputHandler = handler;
|
|
371
|
+
const pending = this.pendingManagedInput;
|
|
372
|
+
this.pendingManagedInput = undefined;
|
|
373
|
+
if (pending)
|
|
374
|
+
void this.handleManagedInput(pending.id, pending.event);
|
|
375
|
+
}
|
|
376
|
+
async handleManagedInput(id, event) {
|
|
377
|
+
if (typeof id !== "string")
|
|
378
|
+
return;
|
|
379
|
+
try {
|
|
380
|
+
if (!this.inputHandler || this.managedInputFailure)
|
|
381
|
+
throw Error("Managed MQTT input handler is unavailable");
|
|
382
|
+
await this.inputHandler(event);
|
|
383
|
+
this.worker.postMessage({ command: "inputComplete", id, status: "success" });
|
|
384
|
+
}
|
|
385
|
+
catch (error) {
|
|
386
|
+
this.managedInputFailure = error instanceof Error ? error : Error("Managed MQTT input failed");
|
|
387
|
+
this.worker.postMessage({ command: "inputComplete", id, status: "error" });
|
|
388
|
+
this.event.emit("error", { code: 0, message: "Managed MQTT input failed; original input retained, clean migration requires review" });
|
|
389
|
+
}
|
|
390
|
+
}
|
|
323
391
|
/**
|
|
324
392
|
* Sets the publisher active state.
|
|
325
393
|
*
|
|
@@ -366,6 +434,8 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
366
434
|
}
|
|
367
435
|
validateHandoverState(input) {
|
|
368
436
|
const state = mqttProxyHandoverStateSchema.parse(input);
|
|
437
|
+
if (!this.unsParameters?.allowNullData && state.values.some(entry => entry.value === null))
|
|
438
|
+
throw Error("MQTT successor did not opt into typed null data");
|
|
369
439
|
if (!this.stateCompatibility || state.compatibility !== this.stateCompatibility)
|
|
370
440
|
throw Error("MQTT destination, subscriptions or calculation-state contract changed; review migration compatibility");
|
|
371
441
|
if (state.instanceName !== this.instanceName || this.lastValues.size || this.currentSequenceId.size)
|
|
@@ -376,7 +446,10 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
376
446
|
const state = mqttProxyHandoverStateSchema.parse(input);
|
|
377
447
|
if (state.instanceName !== this.instanceName || this.lastValues.size || this.currentSequenceId.size)
|
|
378
448
|
throw Error("MQTT successor state is not empty or belongs to another proxy");
|
|
379
|
-
this.lastValues = new Map(state.values.map(entry => [entry.topic, {
|
|
449
|
+
this.lastValues = new Map(state.values.map(entry => [entry.topic, {
|
|
450
|
+
value: entry.value, uom: entry.uom, timestamp: new Date(entry.timestamp),
|
|
451
|
+
...(entry.valueType ? { valueType: entry.valueType } : {}),
|
|
452
|
+
}]));
|
|
380
453
|
this.currentSequenceId = new Map(state.sequences.map(([topic, sequence]) => [topic, sequence]));
|
|
381
454
|
}
|
|
382
455
|
async getHandoverOffer() {
|
|
@@ -458,10 +531,22 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
458
531
|
*/
|
|
459
532
|
async setSubscriberPassiveAndDrainQueue(strict = false) {
|
|
460
533
|
const mqttWorkerData = await this.setSubscriberPassive(strict);
|
|
534
|
+
if (this.managedInputFailure)
|
|
535
|
+
throw this.managedInputFailure;
|
|
461
536
|
await this.flush();
|
|
462
537
|
logger.info(`${this.instanceNameWithSuffix} - Subscriber set to passive and queue drained.`);
|
|
463
538
|
return mqttWorkerData;
|
|
464
539
|
}
|
|
540
|
+
/** Ordinary stop drains received owned input; live handover keeps its cutover cursor. */
|
|
541
|
+
async drainInputForStop() {
|
|
542
|
+
if (this.unsParameters.managedInput) {
|
|
543
|
+
await this.subscriberControl("drainSubscriberInput");
|
|
544
|
+
if (this.managedInputFailure)
|
|
545
|
+
throw this.managedInputFailure;
|
|
546
|
+
}
|
|
547
|
+
else
|
|
548
|
+
await this.setSubscriberPassiveAndDrainQueue();
|
|
549
|
+
}
|
|
465
550
|
async drainPublishes(timeoutMs = UnsMqttProxy.DEFAULT_DRAIN_TIMEOUT_MS) {
|
|
466
551
|
if (this.workerFailure) {
|
|
467
552
|
throw this.workerFailure;
|
|
@@ -470,7 +555,7 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
470
555
|
await this.requestPublishQueue("flushPublishes", timeoutMs);
|
|
471
556
|
return;
|
|
472
557
|
}
|
|
473
|
-
if (this.pendingEnqueues.size === 0 && this.pendingPublishCompletions.size === 0) {
|
|
558
|
+
if (this.pendingEnqueues.size === 0 && this.pendingPublishCompletions.size === 0 && !this.capacityWaiters.length && !this.capacityReservations) {
|
|
474
559
|
return;
|
|
475
560
|
}
|
|
476
561
|
await new Promise((resolve, reject) => {
|
|
@@ -542,6 +627,12 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
542
627
|
: "table" in attrEntry && attrEntry.table
|
|
543
628
|
? { table: attrEntry.table, createdAt: attrEntry.createdAt, expiresAt: attrEntry.expiresAt }
|
|
544
629
|
: (() => { throw new Error("Attribute entry must include exactly one of data/table/message"); })();
|
|
630
|
+
if (message.data?.value === null) {
|
|
631
|
+
if (!this.unsParameters?.allowNullData)
|
|
632
|
+
throw Error("Publisher must opt into typed null data");
|
|
633
|
+
if (mode !== MessageMode.Raw)
|
|
634
|
+
throw Error("Null data cannot be differentiated");
|
|
635
|
+
}
|
|
545
636
|
const packet = await UnsPacket.unsPacketFromUnsMessage(message);
|
|
546
637
|
const singleMsg = {
|
|
547
638
|
topic,
|
|
@@ -569,7 +660,7 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
569
660
|
description: attrDescription,
|
|
570
661
|
tags: attrEntry.tags,
|
|
571
662
|
attributeNeedsPersistence: attrEntry.attributeNeedsPersistence,
|
|
572
|
-
valueType: attrEntry.valueType,
|
|
663
|
+
valueType: attrEntry.valueType ?? (message.data?.value === null ? packet.message.data?.valueType : undefined),
|
|
573
664
|
presentationKind: attrEntry.presentationKind,
|
|
574
665
|
defaultAggregation: attrEntry.defaultAggregation,
|
|
575
666
|
counterResetPolicy: attrEntry.counterResetPolicy,
|
|
@@ -748,7 +839,7 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
748
839
|
if (lastValueEntry && lastValueEntry.uom === newUom && typeof lastValueEntry.value === typeof newValue) {
|
|
749
840
|
const intervalBetweenMessages = currentTime.getTime() - lastValueEntry.timestamp.getTime();
|
|
750
841
|
const lastValue = lastValueEntry.value;
|
|
751
|
-
this.lastValues.set(publishTopic, { value: newValue, uom: newUom, timestamp: currentTime });
|
|
842
|
+
this.lastValues.set(publishTopic, { value: newValue, uom: newUom, timestamp: currentTime, ...(newValue === null ? { valueType: msg.packet.message.data.valueType } : {}) });
|
|
752
843
|
// Compute the delta and manage cumulative resets
|
|
753
844
|
if (valueIsCumulative == true && typeof newValue === "number" && typeof lastValue === "number") {
|
|
754
845
|
// Skip if newValue is 0 (likely a glitch)
|
|
@@ -762,7 +853,7 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
762
853
|
await this.enqueueMessageToWorkerQueue(publishTopic, JSON.stringify(msg.packet));
|
|
763
854
|
}
|
|
764
855
|
else {
|
|
765
|
-
this.lastValues.set(publishTopic, { value: newValue, uom: newUom, timestamp: currentTime });
|
|
856
|
+
this.lastValues.set(publishTopic, { value: newValue, uom: newUom, timestamp: currentTime, ...(newValue === null ? { valueType: msg.packet.message.data.valueType } : {}) });
|
|
766
857
|
logger.debug(`${this.instanceNameWithSuffix} - Need one more packet to calculate interval on topic ${publishTopic}`);
|
|
767
858
|
if (valueIsCumulative === false) {
|
|
768
859
|
await this.enqueueMessageToWorkerQueue(publishTopic, JSON.stringify(msg.packet));
|
|
@@ -872,6 +963,8 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
872
963
|
this.rejectOutstandingPublishes(reason);
|
|
873
964
|
}
|
|
874
965
|
rejectOutstandingPublishes(reason) {
|
|
966
|
+
for (const waiter of this.capacityWaiters.splice(0))
|
|
967
|
+
waiter.reject(reason);
|
|
875
968
|
for (const pending of this.pendingEnqueues.values()) {
|
|
876
969
|
pending.reject(reason);
|
|
877
970
|
}
|
|
@@ -888,6 +981,11 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
888
981
|
}
|
|
889
982
|
}
|
|
890
983
|
notifyDrainWaiters() {
|
|
984
|
+
if (!this.workerFailure && !this.publishesSealed && this.lifecycleState === "running" && this.capacityWaiters.length
|
|
985
|
+
&& this.pendingEnqueues.size + this.pendingPublishCompletions.size + this.capacityReservations < this.unsParameters.maxPendingPublishes) {
|
|
986
|
+
this.capacityReservations++;
|
|
987
|
+
this.capacityWaiters.shift().resolve();
|
|
988
|
+
}
|
|
891
989
|
if (this.workerFailure) {
|
|
892
990
|
const waiters = this.drainWaiters.splice(0);
|
|
893
991
|
for (const waiter of waiters) {
|
|
@@ -898,7 +996,7 @@ export default class UnsMqttProxy extends UnsProxy {
|
|
|
898
996
|
}
|
|
899
997
|
return;
|
|
900
998
|
}
|
|
901
|
-
if (this.pendingEnqueues.size !== 0 || this.pendingPublishCompletions.size !== 0) {
|
|
999
|
+
if (this.pendingEnqueues.size !== 0 || this.pendingPublishCompletions.size !== 0 || this.capacityWaiters.length || this.capacityReservations) {
|
|
902
1000
|
return;
|
|
903
1001
|
}
|
|
904
1002
|
const waiters = this.drainWaiters.splice(0);
|