SAP / SAP/cloud-sdk-java

DefaultHttpDestination.equals() change in 5.34.0 causes MT sidecar 408 timeouts under load

オープン
#1,268 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

主要言語
Java
スター
41
フォーク
33
平均マージ
18時間 34分
マージ済み PR(30日)
19

説明

Summary

After upgrading from 5.33.0 to 5.34.0, a Java CAP application that uses the MTX sidecar (@sap/cds-mtxs) for multi-tenancy experiences HTTP 408 Request Timeout responses from the sidecar during tenant subscribe/unsubscribe. The issue is consistently reproducible on a loaded CI environment (Jenkins), though not locally where the sidecar responds fast enough.

Affected versions

  • Broken: 5.34.0
  • Working: 5.33.0

Root cause analysis

PR #1095 ("Fix unexpected connection-pool shut-down") changed DefaultHttpDestination.equals() and hashCode() to now include customHeaderProviders and headerProvidersFromClassLoading in the comparison (previously these were excluded).

DefaultHttpDestination equality is the cache key for the Cloud SDK HTTP client cache (DefaultApacheHttpClient5Cache). MT scenarios attach per-tenant header providers (auth/token headers) to destinations. Before this change, all tenants pointing at the same sidecar URI shared one HttpClient and one connection pool. After this change, each tenant's destination is a distinct cache key → a new HttpClient + connection pool is created per subscribe/unsubscribe call → rapid connection pool churn against a single sidecar process → the sidecar starts returning 408.

The relevant call chain (in com.sap.cds:cds-feature-mt):

ProvisioningService.subscribe()
  → ServiceCallImpl.execute()
  → HttpClientFactory.getHttpClient(destination)     // calls ApacheHttpClient5Accessor
  → sidecar PUT /-/cds/saas-provisioning/tenant/{id}
  ← HTTP 408
  → InternalError("Unexpected return code 408")      // 408 is not in the retry set {500,502,503,504}
  → MtxSidecarDeploymentHandler.onSubscribe() throws
  → HTTP 500 to the subscribe caller

Evidence

Two consecutive CI builds on the same PR branch both failed with the exact same stack:

Caused by: com.sap.cds.feature.mt.lib.subscription.exceptions.InternalError: Unexpected return code 408
  at com.sap.cds.feature.mt.lib.subscription.ProvisioningService.lambda$new$1(ProvisioningService.java:80)
  ...
Caused by: com.sap.cds.feature.mt.lib.subscription.exceptions.InternalError: Unexpected return code 408
  at com.sap.cds.feature.mt.lib.subscription.ProvisioningService.lambda$new$1(ProvisioningService.java:80)

Failing test: com.sap.mtx.multitenancy.SubscribeAndUnsubscribeTest.onBoardAndOffBoardNewTenant (expects HTTP 201, gets 500). All other 13 commits in the 5.33.0→5.34.0 range are dependency bumps that are already overridden by the consuming project's own version pins — the only behaviour-changing commit is #1095.

Steps to reproduce

  1. Run an MTX-sidecar-based CAP Java application's integration tests that subscribe/unsubscribe multiple tenants in rapid succession (e.g. the mtx-local module of cds-services).
  2. Each subscribe/unsubscribe call hits the sidecar via ApacheHttpClient5Accessor.getHttpClient(destination) where the destination carries tenant-specific header providers.
  3. With 5.34.0, a new HttpClient + connection pool is allocated per tenant on every call → pool exhaustion / timeout after several tenants → 408 from the sidecar.
  4. With 5.33.0, all same-URI destinations share one HttpClient and pool → no exhaustion → sidecar responds 200/202.

Suggested fix

Options:

  • On the cloud-sdk side: consider whether the HTTP-client cache should key on something coarser (e.g. URI only, or URI + a stable identity of the header providers) rather than full header provider equality, especially for the per-request-dynamic providers used in MT scenarios.
  • As a workaround: the consuming application can pin cloud.sdk.version=5.33.0 until this is resolved.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

まず、PR #1095 における DefaultHttpDestination.equals() と hashCode() の変更を、DefaultApacheHttpClient5Cache の動作と比較します。com.sap.mtx.multitenancy.SubscribeAndUnsubscribeTest.onBoardAndOffBoardNewTenant を使って失敗を再現し、ApacheHttpClient5Accessor.getHttpClient() に渡される destination を追跡します。完了の条件は、負荷時に MT の subscribe/unsubscribe シナリオで 408 または HTTP 500 のレスポンスが発生しなくなることです。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
java
領域
backend, networking
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
48/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。