plugins/aem/cloud-service/skills/code-assessment/outbound-call-timeouts/SKILL.md
[BETA] AEM Cloud Service expert skill — add explicit connect/read/socket timeouts to outbound HTTP clients constructed without one (Apache HttpClient 4.x/5.x, OkHttp, JDK java.net.http.HttpClient), including the JDK per-request read timeout on HttpRequest. Use for "add HTTP timeouts", "this external/outbound call has no timeout", or a scan that flags a timeout-less client. Highest-frequency CSO outage cause: a client on default (effectively infinite) timeouts holds request threads on a slow upstream until the Jetty pool saturates and the site goes down. The analyzer locates timeout-less construction sites; mechanical per-library remediation applies CSO-backed default timeouts (recipe.md). This skill is in beta. Verify all outputs before applying them to production projects.
npx skillsauth add adobe/skills outbound-call-timeoutsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Beta Skill: This skill is in beta and under active development. Results should be reviewed carefully before use in production. Report issues at https://github.com/adobe/skills/issues
This pattern is executed by the code-assessment runbook — follow
../references/runbook.mdfor the full flow (preflight → plan → apply → verify, run log). This skill supplies the detection + recipe the runbook applies.
An HTTP client built without an explicit timeout inherits effectively-infinite connect/read defaults. When an upstream slows or hangs, every request thread blocks on that call; on AEM CS the shared Jetty request-thread pool saturates and the whole instance stops serving — this is the single highest-frequency cause in the CSO outage dataset. The fix sets a connect timeout and a read/socket timeout (and, for Apache, a connection-request timeout) so a stuck upstream fails fast instead of taking the instance down.
HttpClients.createDefault() / HttpClientBuilder.create()…build(), OkHttp new OkHttpClient() / …newBuilder()…build(), or JDK HttpClient.newHttpClient() / HttpClient.newBuilder()…build() — with no timeout configured in the same scope.outbound-call-timeouts.RequestConfig, setConnectTimeout, connectTimeout, Timeout.of…, Duration.of… in scope); per-request timeouts only is a partial case the recipe handles.Detection is performed by the analyzer (../scripts/analyze.sh), run by the runbook:
bash ../scripts/analyze.sh <workspace-root> --pattern outbound-call-timeouts
Match criteria (what the detector flags):
HttpClientBuilder, HttpClients, OkHttpClient, HttpClient) and a construction marker (.createDefault, .newBuilder, .newHttpClient, .build(, new HttpClientBuilder, new OkHttpClient), emitted at the outermost fluent-chain link. Suppressed when the enclosing method (or, for a field initializer, the enclosing class) contains any client timeout token (setConnectTimeout, setSocketTimeout, setConnectionRequestTimeout, setResponseTimeout, connectTimeout, readTimeout, writeTimeout, callTimeout, RequestConfig, Timeout.of, Duration.of).HttpRequest.newBuilder()…build() chain (gated to java.net.http.HttpRequest by import/FQN so other libraries' HttpRequest is not matched). Suppressed when the chain itself sets .timeout(...). This is the per-request read timeout the JDK has no client-level setter for.Parse-level only — no type resolution, so matching is textual.
Conservative posture (intentional false negatives). If a timeout is configured anywhere in the enclosing scope the site is skipped, even if it is the wrong knob — the detector prefers missing a real issue to flagging a safe client. The residual false-positive case (a client whose timeout is supplied from a different method — an injected RequestConfig or a shared HttpClientFactory) is caught at remediation by the recipe's skip policy, not at detection.
self-evident — fixed default timeouts are applied; the developer supplies nothing up front (they review the resulting diff). Defaults: connect 3 s, read/socket 8 s, Apache connection-request 2 s — bounded against the infinite-hang outage and CSO-aligned; tighten in review if the upstream's SLA is stricter. The library and edit template are picked deterministically from the construction site's import package (org.apache.http → Apache 4.x, org.apache.hc → Apache 5.x, okhttp3 → OkHttp, java.net.http → JDK). All are fully mechanical — for the JDK client the connect timeout goes on the client, and JDK HttpRequest.newBuilder()…build() chains are detected and fixed separately with a per-request .timeout(...). Cases that cannot be completed deterministically (non-standard construction shapes) are skipped with a reason, never guessed.
connectionRequestTimeout (pool-checkout) — a saturated connection pool otherwise blocks regardless of socket timeoutRequestConfig.setSocketTimeout(int ms) vs 5.x Timeout / setResponseTimeout; OkHttp Duration overloads; JDK connectTimeout(Duration) + per-request .timeout(Duration)0 / infinite; values are seconds-scale, not minutesRead recipe.md in full before editing: input contract, locator, per-library remediation (Apache 4.x/5.x, OkHttp, JDK java.net.http), recommended values, skip policy, before/after, editing strategy.
The skill never commits. See ../references/git-workflow.md for git vs in-place handoff and the suggested commit message.
tools
Use the run-workflow MCP to discover, compose, execute, publish, and save Adobe Firefly workflows. TRIGGER when: user asks what actions are available, what the MCP can do, how to process images/video/3D via workflow, wants to build/run/save/publish a workflow, OR pastes any workflow/batch/execution ID. BARE ID (UUID/workflowId/batchId) = INSPECT ONLY — call inspect_run, NEVER run_workflow_submit. ALWAYS call list_actions first for capability/discovery questions. DO NOT TRIGGER for direct Firefly API calls without MCP (use firefly-api-specs).
tools
Run predefined featured workflows via run-workflow MCP. TRIGGER when user names a featured workflow (retargeting, banners at scale, localization, packaging, banner advertising, etc.) or asks to run a known marketing/production workflow. Requires run-workflow MCP. ALWAYS call get_featured_workflow before compose_workflow. DO NOT TRIGGER for custom one-off workflows with no named template — use run-workflow skill.
tools
Migrate an Adobe Commerce App Builder project from the Integration Starter Kit or Checkout Starter Kit to the new App Management approach. Run from the root of the App Builder project to be migrated. Pass --auto to skip confirmation prompts (suitable for CI or batch use) — auto mode prints a summary of all Q&A questions answered with their defaults. Pass --doc-scan-only to scan README.md and env.dist for outdated content without modifying any files. Use when the user wants to migrate an App Builder project from the Integration Starter Kit or Checkout Starter Kit to the App Management approach, or mentions upgrading their Adobe Commerce extension architecture.
development
Add or modify webhook interceptors in an Adobe Commerce app. Use when the user wants to intercept Commerce operations to validate input, append data, or modify behavior — before or after execution. Requires a base app initialized with commerce-app-init.