UNPKG

@ydbjs/topic

Version:

YDB Topics client for publish-subscribe messaging. Provides at-least-once delivery, exactly-once publishing, FIFO guarantees, and scalable message processing for unstructured data.

106 lines 5.25 kB
import { nextTick } from 'node:process'; import { StatusIds_StatusCode } from '@ydbjs/api/operation'; import { TopicServiceDefinition } from '@ydbjs/api/topic'; import { loggers } from '@ydbjs/debug'; import { YDBError } from '@ydbjs/error'; import { defaultRetryConfig, retry } from '@ydbjs/retry'; import { _send_init_request } from './_init_request.js'; import { _on_init_response } from './_init_response.js'; import { _on_start_partition_session_request } from './_start_partition_session_request.js'; import { _on_stop_partition_session_request } from './_stop_partition_session_request.js'; import { _on_end_partition_session } from './_end_partition_session.js'; import { _on_read_response } from './_read_response.js'; let dbg = loggers.topic.extend('reader'); export let _consume_stream_tx = async function consume_stream_tx(state) { if (state.disposed) { return; } let signal = state.controller.signal; await state.driver.ready(signal); state.tx.onRollback((reason) => { state.controller.abort(reason); }); await retry({ ...defaultRetryConfig, signal }, async (signal) => { state.outgoingQueue.close(); state.outgoingQueue.reset(); dbg.log('connecting to the tx stream with consumer %s', state.options.consumer); // If we have buffered messages, we need to clear them before connecting to the stream. if (state.buffer.length) { dbg.log('has %d messages in the buffer before connecting to the stream, clearing it', state.buffer.length); state.buffer.length = 0; // Clear the buffer before connecting to the stream state.freeBufferSize = state.maxBufferSize; // Reset free buffer size } // Clear any existing partition sessions before reconnecting if (state.partitionSessions.size) { dbg.log('has %d partition sessions before connecting to the stream, stopping them', state.partitionSessions.size); for (let partitionSession of state.partitionSessions.values()) { partitionSession.stop(); } state.partitionSessions.clear(); } // Clear read offsets for transaction reader state.readOffsets.clear(); let stream = state.driver .createClient(TopicServiceDefinition) .streamRead(state.outgoingQueue, { signal }); nextTick(() => { _send_init_request({ queue: state.outgoingQueue, consumer: state.options.consumer, topicsReadSettings: state.topicsReadSettings, }); }); // Log all messages from server. let dbgrpc = dbg.extend('grpc'); for await (let chunk of stream) { state.controller.signal.throwIfAborted(); dbgrpc.log('receive %s with status %d', chunk.serverMessage.value?.$typeName, chunk.status); if (chunk.status !== StatusIds_StatusCode.SUCCESS) { let error = new YDBError(chunk.status, chunk.issues); dbg.log('received error from server: %s', error.message); throw error; } // Handle the server message based on type if (chunk.serverMessage.case === 'initResponse') { void _on_init_response({ outgoingQueue: state.outgoingQueue, freeBufferSize: state.freeBufferSize, }, chunk.serverMessage.value); } else if (chunk.serverMessage.case === 'startPartitionSessionRequest') { void _on_start_partition_session_request({ partitionSessions: state.partitionSessions, outgoingQueue: state.outgoingQueue, ...(state.options.onPartitionSessionStart && { onPartitionSessionStart: state.options.onPartitionSessionStart, }), }, chunk.serverMessage.value); } else if (chunk.serverMessage.case === 'stopPartitionSessionRequest') { void _on_stop_partition_session_request({ partitionSessions: state.partitionSessions, outgoingQueue: state.outgoingQueue, buffer: state.buffer, disposed: state.disposed, ...(state.options.onPartitionSessionStop && { onPartitionSessionStop: state.options.onPartitionSessionStop, }), }, chunk.serverMessage.value); } else if (chunk.serverMessage.case === 'endPartitionSession') { void _on_end_partition_session({ partitionSessions: state.partitionSessions, }, chunk.serverMessage.value); } else if (chunk.serverMessage.case === 'readResponse') { void _on_read_response({ buffer: state.buffer, updateFreeBufferSize: (deltaBytes) => { state.freeBufferSize += deltaBytes; }, }, chunk.serverMessage.value); } } }); }; //# sourceMappingURL=_consume_stream_tx.js.map