[英]How to ACK using Google PubSub (@google-cloud/pubsub)
[英]Google Cloud PubSub not ack messages
我们拥有基于GCP PubSub的发布者和订阅者系统。 订户处理单个消息的时间很长,大约1分钟。 我们已经将订户确认截止时间设置为600秒(10分钟)(最大),以确保pubsub不会太早开始重新交付,因为基本上我们在这里运行时间很长。
我看到了PubSub的这种行为。 当代码发送确认和监视器确认PubSub确认请求已被接受并且确认本身以成功状态完成时,未确认消息的总数仍然相同。
图表上的指标显示的总和,均值和均值聚合对齐器均相同。 在上面的图片中,对齐器是平均的,没有启用减速器。
我正在使用@ google-cloud / pubsub Node.js库。 已经尝试了不同的版本(0.18.1、0.22.2、0.24.1),但是我想问题不在其中。
以下类可用于检查。
TypeScript 3.1.1,节点8.xx-10.xx
import { exponential, Backoff } from "backoff";
const pubsub = require("@google-cloud/pubsub");
export interface IMessageHandler {
handle (message): Promise<void>;
}
export class PubSubSyncListener {
private readonly client;
private listener: Backoff;
private runningOperations: Promise<unknown>[] = [];
constructor (
private readonly handler: IMessageHandler,
private readonly options: {
/**
* Maximal messages number to be processed simultaniosly.
* Listener will try to keep processing number as close to provided value
* as possible.
*/
maxMessages: number;
/**
* Formatted full subscrption name /projects/{projectName}/subscriptions/{subscriptionName}
*/
subscriptionName: string;
/**
* In milliseconds
*/
minimalListenTimeout?: number;
/**
* In milliseconds
*/
maximalListenTimeout?: number;
}
) {
this.client = new pubsub.v1.SubscriberClient();
this.options = Object.assign({
minimalListenTimeout: 300,
maximalListenTimeout: 30000
}, this.options);
}
public async listen () {
this.listener = exponential({
maxDelay: this.options.maximalListenTimeout,
initialDelay: this.options.minimalListenTimeout
});
this.listener.on("ready", async () => {
if (this.runningOperations.length < this.options.maxMessages) {
const [response] = await this.client.pull({
subscription: this.options.subscriptionName,
maxMessages: this.options.maxMessages - this.runningOperations.length
});
for (const m of response.receivedMessages) {
this.startMessageProcessing(m);
}
this.listener.reset();
this.listener.backoff();
} else {
this.listener.backoff();
}
});
this.listener.backoff();
}
private startMessageProcessing (message) {
const index = this.runningOperations.length;
const removeFromRunning = () => {
this.runningOperations.splice(index, 1);
};
this.runningOperations.push(
this.handler.handle(this.getHandlerMessage(message))
.then(removeFromRunning, removeFromRunning)
);
}
private getHandlerMessage (message) {
message.message.ack = async () => {
const ackRequest = {
subscription: this.options.subscriptionName,
ackIds: [message.ackId]
};
await this.client.acknowledge(ackRequest);
};
return message.message;
}
public async stop () {
this.listener.reset();
this.listener = null;
await Promise.all(
this.runningOperations
);
}
}
这基本上是消息的异步提取和立即确认的部分实现。 因为提出的解决方案之一是使用同步拉动。
如果我没有记错问题的症状,那么我在Java存储库中发现了类似的报告问题。
https://github.com/googleapis/google-cloud-java/issues/3567
这里的最后一个细节是,确认似乎对少量请求有效。 如果我在pubsub中触发单个消息然后立即对其进行处理,则未传递的消息数会减少(由于之前只有一条消息而下降为0)。
问题本身-发生了什么?为什么收到确认消息后未确认消息的数量没有减少?
要引用该文档 ,您正在使用的subscription / num_undelivered_messages指标是“订阅中未确认的消息(即积压消息)的数量。 每60秒采样一次 。 采样后,最多120秒不可见数据。 ”
您不应期望此指标在确认消息后立即下降。 此外,听起来好像您正试图将pubsub用于恰好一次的传递情况,试图确保不会再次传递该消息。 Cloud Pub / Sub不提供这些语义。 它至少提供一次语义。 换句话说,即使您已经收到一个值,确认了该值,收到了ack响应,并且看到指标从1下降到0,对于同一工人或另一个工人,仍然有可能并正确地接收到该消息的精确副本。 。 尽管在实践中这不太可能,但您应该专注于构建具有重复容忍能力的系统,而不是尝试确保确认成功,这样就不会重新传递您的消息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.