pubsub: "Operation attempted on ended Span" when a modack is flushed after the message was acked
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 82/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- node.js, typescript
- 領域
- backend, observability
調査の方向性
handwritten/pubsub/src/telemetry-tracing.tsでcreateAckRpcSpanとcreateModackRpcSpanの周辺を読み、その後、handwritten/pubsub/src/message-queues.tsとsubscriber.tsに記載されたキューの流れを確認してください。リンクされたgist、または同等の焦点を絞ったテストで、終了済みspanのケースを再現してください。ackとmodackのトレーシングが終了済みspanのメソッドを呼び出さず、SDKがエラーをログに記録しなくなったことをテストで確認できれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Please make sure you have searched for information in the following guides.
- Search the issues already opened: https://github.com/GoogleCloudPlatform/google-cloud-node/issues
- Check the API's issue tracker (related, but publisher-side only: googleapis/nodejs-pubsub#2110, googleapis/nodejs-pubsub#2119)
Library Name
@google-cloud/pubsub (reproduced on 6.0.1 and 6.4.1)
A screenshot that you have tested with "Try this API".
N/A. This is a client-side bug in the library's OpenTelemetry instrumentation. No API call is needed to reproduce it.
Link to the code that reproduces this issue. A link to a public Github Repository or gist with a minimal reproduction.
https://gist.github.com/tmair/b9c1cd2b558e40eb8423566580d0a244
A step-by-step description of how to reproduce the issue, based on the linked reproduction.
npm install && npm start- The repro registers an SDK
BasicTracerProvider, enables pubsub tracing, starts a subscribe span and ends it. This simulates a message that was acked while a modack for it was still queued. It then callsPubsubSpans.createModackRpcSpan([subscribeSpan], ...), which is whatModAckQueue._sendBatchdoes when the queue flushes. - The OpenTelemetry SDK logs:
Cannot execute the operation on ended Span {traceId: ..., spanId: ...} Error: Operation attempted on ended Span {traceId: ..., spanId: ...}
at SpanImpl._isSpanEnded (.../@opentelemetry/sdk-trace/build/src/Span.js:342:27)
at SpanImpl.addLink (.../@opentelemetry/sdk-trace/build/src/Span.js:170:18)
at .../@google-cloud/pubsub/build/src/telemetry-tracing.js:421:23
at Array.forEach (<anonymous>)
at PubsubSpans.createModackRpcSpan (...)
We see this in production on a subscriber created with enableOpenTelemetryTracing: true and @opentelemetry/sdk-node (sdk-trace 2.11.0). It happens for messages whose processing takes long enough to get a lease extension. The stack trace from production:
Error: Operation attempted on ended Span {traceId: 8d525b04ad08368f161db86c3d9c950d, spanId: 6419191f508e8c82}
at SpanImpl._isSpanEnded (/app/otel-instrumentation/node_modules/@opentelemetry/sdk-trace/build/src/Span.js:342:27)
at SpanImpl.addLink (/app/otel-instrumentation/node_modules/@opentelemetry/sdk-trace/build/src/Span.js:170:18)
at /app/node_modules/@google-cloud/pubsub/build/src/telemetry-tracing.js:420:23
at Array.forEach (<anonymous>)
at PubsubSpans.createModackRpcSpan (/app/node_modules/@google-cloud/pubsub/build/src/telemetry-tracing.js:418:26)
at /app/node_modules/@google-cloud/pubsub/build/src/message-queues.js:538:54
at Array.map (<anonymous>)
at ModAckQueue._sendBatch (/app/node_modules/@google-cloud/pubsub/build/src/message-queues.js:533:57)
at async ModAckQueue.flush (/app/node_modules/@google-cloud/pubsub/build/src/message-queues.js:262:29)
A clear and concise description of what the bug is, and what you expected to happen.
The ack and modack queues flush independently, but both keep a reference to the message's subscribe span:
- The lease manager extends the deadline of a message that is still being processed.
MessageQueue.addstoresmessage.parentSpanastracingSpanin the modack batch (message-queues.ts#L254). - The handler calls
message.ack().Subscriber.ackwaits only for the ack queue to flush and then callsmessage.endParentSpan()(subscriber.ts#L889-L892). - The modack queue flushes afterwards.
createModackRpcSpancallsm.addLink(...)on the subscribe span that has already ended (telemetry-tracing.ts#L602-L608).
The OpenTelemetry SDK rejects the addLink call and logs an error through diag. Nothing is thrown and the messages are acked correctly, but every affected message produces an error log entry, which shows up as an error group in Cloud Error Reporting. createAckRpcSpan uses the same pattern (telemetry-tracing.ts#L554-L560) and could hit the same problem for a span that ended in another way (e.g. nack or shutdown).
Expected: the library does not call methods on spans that it has already ended, so no errors are logged.
Suggested fix: skip spans that are no longer recording in createModackRpcSpan and createAckRpcSpan:
messageSpans.forEach(m => {
if (m && isSampled(m) && m.isRecording()) {
m.addLink({context: span.spanContext()});
}
});
An SDK span returns isRecording() === false once it has ended, so this skips exactly the failing case. The link from the subscribe span to the RPC span is lost for those messages, but the subscribe span has already been exported at that point anyway.
A clear and concise description WHY you expect this behavior, i.e., was it a recent change, there is documentation that points to this behavior, etc. **
The OpenTelemetry specification does not allow changes to a span after end() has been called ("Implementations SHOULD ignore all subsequent calls to End and any other Span methods"), and the SDK reports such calls as errors. The library ends the subscribe span itself in Subscriber.ack, so it should not modify that span afterwards. The same class of bug was reported for the publisher side in googleapis/nodejs-pubsub#2110 and googleapis/nodejs-pubsub#2119.
- 主要言語
- TypeScript
- スター
- 3.2k
- フォーク
- 732
- 平均マージ
- 3日 7時間
- マージ済み PR(30日)
- 117
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
googleapis/google-cloud-node のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
googleapis/google-cloud-node#9854 ·
メンテナーはふだん 1 日以内に返信
-
storage: V4 getSignedUrl sorts canonical headers with localeCompare, so they disagree with X-Goog-SignedHeaders対応中かも @itsrayeedscodespace が 6 日前に担当しました。 オープンapi: storage
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
googleapis/google-cloud-node#9840 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
firestore: getPartitions() emits gax AutopaginateTrueWarning in every process対応中かも @TheRealDanii が 9 日前に担当しました。 オープンapi: firestore
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
googleapis/google-cloud-node#9736 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 82/100
googleapis/google-cloud-node#9723 ·
メンテナーはふだん 1 日以内に返信
-
spanner: requiring @google-cloud/spanner stops the process from exiting on SIGTERM/SIGINT再び着手できるかも @alkatrivedi が 31 日前に担当しましたが、オープン中のプルリクエストはありません。 オープンapi: spanner
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
googleapis/google-cloud-node#9513 · リアクション 1 件 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
googleapis/google-cloud-node の issue をすべて見る
似ている issue
-
bug UI
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
wardian-app/Wardian#1746 ·
メンテナーはふだん 1 日以内に返信
-
area: interop area: sip-core v3
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
fonoster/routr#705 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
メンテナーはふだん 1 日以内に返信
-
clawsweeper:fix-shape-clear clawsweeper:queueable-fix clawsweeper:source-repro impact:ux-friction issue-rating: 🦞 diamond lobster no-stale P2
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
openclaw/openclaw#198551 · コメント 1 件 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信