David K
03/06/2024, 7:41 PMFabian Wikstrom
03/06/2024, 8:26 PM/**
* Create a consumer with a handle to process messages from the ingress topic. *
* @returns A consumer instance.
*/
export async function createIngressConsumerPulsar(
onMsgReceived: (msg: PulsarMessage) => void,
onMsgProcessed: (msg: PulsarMessage) => void,
onMsgError: (error: Error) => void,
): Promise<PulsarConsumer> {
const ACK_TIMEOUT_MILLIS = 10_000;
const NACK_REDELIVER_TIMEOUT_MILLIS = 30_000;
const DEAD_LETTER_MAX_REDELIVER_COUNT = 3;
const TOPIC = process.env.INTEGRATION_BROKER_INGRESS_PULSAR_TOPIC as string;
const SUBSCRIPTION_NAME = process.env
.INTEGRATION_BROKER_INGRESS_PULSAR_SUBSCRIPTION as string;
const DEAD_LETTER_TOPIC = process.env
.INTEGRATION_BROKER_INGRESS_PULSAR_DLQ_TOPIC as string | undefined;
const DEAD_LETTER_SUBSCRIPTION = process.env
.INTEGRATION_BROKER_INGRESS_PULSAR_DLQ_SUBSCRIPTION as string | undefined;
const IS_DEAD_LETTER_CONSUMER = process.env
.INTEGRATION_BROKER_INGRESS_IS_DEAD_LETTER as string | undefined;
const isDeadLetterConsumer =
IS_DEAD_LETTER_CONSUMER && IS_DEAD_LETTER_CONSUMER === 'true';
if (
!isDeadLetterConsumer &&
(!DEAD_LETTER_TOPIC || !DEAD_LETTER_SUBSCRIPTION)
) {
throw new Error(
'Dead letter topic and subscription are required. (Unless this is the dead letter consumer)',
);
}
<http://logger.info|logger.info>('Creating consumer with topic: ' + TOPIC);
const pulsarClient = PulsarService.getInstance().getClient();
return await pulsarClient.subscribe({
topics: [TOPIC],
subscription: SUBSCRIPTION_NAME,
subscriptionType: 'Shared',
ackTimeoutMs: ACK_TIMEOUT_MILLIS,
nAckRedeliverTimeoutMs: NACK_REDELIVER_TIMEOUT_MILLIS,
batchIndexAckEnabled: true,
listener: (msg, consumer) =>
handleMessage(msg, consumer, onMsgReceived, onMsgProcessed, onMsgError),
deadLetterPolicy:
!isDeadLetterConsumer && DEAD_LETTER_TOPIC && DEAD_LETTER_TOPIC !== TOPIC
? {
initialSubscriptionName: DEAD_LETTER_SUBSCRIPTION,
deadLetterTopic: DEAD_LETTER_TOPIC,
maxRedeliverCount: DEAD_LETTER_MAX_REDELIVER_COUNT,
}
: undefined,
});
}
/**
* Handle a message from the Pulsar consumer.
* Acks if successful, nacks if error is thrown.
* @param msg - Message to handle.
* @param consumer - Consumer that received the message.
* @param onMsgReceived - callback for when a message is received.
* @param onMsgProcessed - callback for when a message is processed.
* @param onMsgError - callback for when a message process errors.
*/
export async function handleMessage(
msg: PulsarMessage,
consumer: PulsarConsumer,
onMsgReceived: (msg: PulsarMessage) => void,
onMsgProcessed: (msg: PulsarMessage) => void,
onMsgError: (error: Error) => void,
): Promise<void> {
onMsgReceived(msg);
const body = msg.getData().toString();
const messageId = msg.getMessageId().toString();
try {
const timestamp = new Date(msg.getPublishTimestamp());
await processMessage({ messageId, body }, timestamp);
await consumer.acknowledge(msg);
onMsgProcessed(msg);
} catch (error) {
consumer.negativeAcknowledge(msg);
onMsgError(error as Error);
return;
}
}Fabian Wikstrom
03/06/2024, 8:27 PMDavid K
03/06/2024, 8:30 PMcatch clause that keeps negativelyAcknowlede the message. These nacks are interpreted by Pulsar as “send me the message again”, so they keep getting sent/error/nack/resent….. over and over again.Fabian Wikstrom
03/06/2024, 8:31 PMmaxRedeliverCount would set a cap of 3 redeliveres before sending to DLQDavid K
03/06/2024, 8:32 PMFabian Wikstrom
03/06/2024, 8:32 PMDavid K
03/06/2024, 8:34 PMDavid K
03/06/2024, 8:34 PMDavid K
03/06/2024, 8:35 PMFabian Wikstrom
03/06/2024, 8:36 PMisDeadLetterConsumer=trueDavid K
03/06/2024, 8:40 PMFabian Wikstrom
03/06/2024, 8:45 PMFabian Wikstrom
03/06/2024, 8:51 PM"{\n \"x-pulsar-batch-size\": \"7212\",\n \"x-pulsar-num-batch-message\": \"2\"\n}"David K
03/06/2024, 8:54 PMDavid K
03/06/2024, 8:55 PMFabian Wikstrom
03/06/2024, 8:59 PM1.10.0David K
03/06/2024, 8:59 PMDavid K
03/06/2024, 9:00 PMFabian Wikstrom
03/06/2024, 9:03 PMpulsarctl subscriptions peek production/data-broker/ingress-p1-partion-0 ingress-p1-production 1 ✘
[✖] code: 404 reason: Topic <persistent://production/data-broker/ingress-p1-partion-0> not found
hmFabian Wikstrom
03/06/2024, 9:05 PMFabian Wikstrom
03/06/2024, 9:07 PM"{\n \"x-pulsar-batch-size\": \"1749\",\n \"x-pulsar-num-batch-message\": \"2\"\n}"Fabian Wikstrom
03/06/2024, 9:08 PMDavid K
03/06/2024, 9:08 PMFabian Wikstrom
03/06/2024, 9:08 PMFabian Wikstrom
03/06/2024, 9:08 PMDavid K
03/06/2024, 9:09 PMFabian Wikstrom
03/06/2024, 9:10 PMDavid K
03/06/2024, 9:10 PMFabian Wikstrom
03/06/2024, 9:10 PMsharedFabian Wikstrom
03/06/2024, 9:10 PMDavid K
03/06/2024, 9:10 PMDavid K
03/06/2024, 9:11 PMDavid K
03/06/2024, 9:12 PMFabian Wikstrom
03/06/2024, 9:13 PMDavid K
03/06/2024, 9:13 PMDavid K
03/06/2024, 9:14 PMFabian Wikstrom
03/06/2024, 9:15 PMFabian Wikstrom
03/06/2024, 9:16 PMFabian Wikstrom
03/06/2024, 9:43 PMFabian Wikstrom
03/06/2024, 9:49 PMDavid K
03/06/2024, 10:10 PMFabian Wikstrom
03/06/2024, 10:20 PMFabian Wikstrom
03/06/2024, 10:20 PMFabian Wikstrom
03/07/2024, 1:55 PMFabian Wikstrom
03/07/2024, 5:45 PMmaxRedeliverCount and ackTimeoutMs for a subscription?David K
03/07/2024, 5:50 PMFabian Wikstrom
03/07/2024, 7:16 PMDavid K
03/07/2024, 7:49 PMFabian Wikstrom
03/07/2024, 7:52 PMbatchIndexAckEnabled on the consumer but not on the broker