Skip to content

TT-15813: add api-level timeout configuration#8282

Merged
vladzabolotnyi merged 22 commits into
masterfrom
TT-15813
Jun 15, 2026
Merged

TT-15813: add api-level timeout configuration#8282
vladzabolotnyi merged 22 commits into
masterfrom
TT-15813

Conversation

@vladzabolotnyi

@vladzabolotnyi vladzabolotnyi commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Description

Ticket: https://tyktech.atlassian.net/browse/TT-15813

Introduces API-level timeout configuration (global_enforce_timeout) as a middle layer between the gateway-level default and endpoint-level enforced timeouts.

Priority order: endpoint-level → API-level → gateway default

Related Issue

https://tyktech.atlassian.net/browse/TT-15813

Motivation and Context

Previously, users could only configure timeouts globally (affecting all APIs) or per-endpoint (tedious and error-prone). This change adds a middle layer so a single timeout value can be applied across all endpoints of a given API, while still allowing individual endpoints to override it.

How This Has Been Tested

Unit tests:

  • TestRuleValidateGlobalEnforceTimeout_Validate — validator rejects negative durations
  • TestUpstream/enforce_timeout — OAS Fill/ExtractTo round-trips for enabled, disabled, sub-second, and zero cases
  • TestUpstreamEnforceTimeoutSchema — OAS JSON schema rejects missing enabled, bad duration format, and non-string duration
  • TestSchema_GlobalEnforceTimeout — classic apidef schema.json accepts valid string durations
  • TestSetDisabledFlagsSetDisabledFlags correctly sets GlobalEnforceTimeoutDisabled=true when no timeout is configured
  • TestXTykGateway_Lint — strict schema validation passes with the new field populated

Integration tests:

  • TestAPILevelTimeout — covers: timeout triggers on slow upstream, no trigger on fast upstream, API-level overrides gateway default, endpoint-level overrides API-level, API-level applies across all endpoints without an override, disabled API-level falls back to gateway default

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Refactoring or add test (improvements in base code or adds test coverage to functionality)

Checklist

  • I ensured that the documentation is up to date
  • I explained why this PR updates go.mod in detail with reasoning why it's required — no go.mod changes
  • I would like a code coverage CI quality gate exception and have explained why

Implementation Notes (for reviewer)

New apidef fields (on VersionInfo, inside version_data.versions.<version_name>):

  • global_enforce_timeout tyktime.ReadableDuration — human-readable duration (e.g. "500ms", "5s", "2m")
  • global_enforce_timeout_disabled bool — allows OAS to round-trip enabled: false with a non-zero duration without losing the value

OAS contract:

x-tyk-api-gateway:
  upstream:
    enforceTimeout:
      enabled: true
      duration: 5s

Classic apidef contract

{
  "version_data": {
    "versions": {
      "Default": {
        "global_enforce_timeout": "5s",
        "global_enforce_timeout_disabled": false
      }
    }
  }
}

Demo

Each version on Classic API has its unique api-level timeout

classic-api-versions-timeout.mov

Api level timeout with OAS

api-level-timeout-oas.mov

Mongo doc new fields representation

image

Ticket Details

TT-15813
Status In Dev
Summary [BE] Feature Request: API-Level Timeout Configuration

Generated at: 2026-06-05 07:48:23

Ticket Details

TT-15813
Status In Dev
Summary [BE] Feature Request: API-Level Timeout Configuration

Generated at: 2026-06-05 07:56:06

@probelabs

probelabs Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

This PR introduces an API-level timeout configuration, creating a new layer of control between the global gateway-level default and specific endpoint-level timeouts. This feature allows developers to set a uniform timeout for all endpoints within an API definition, simplifying configuration and reducing redundancy. The new timeout precedence is: Endpoint-level → API-level → Gateway default.

Files Changed Analysis

The changes are primarily located in the apidef and gateway packages.

  • apidef/: The core API definition (APIDefinition) is extended with GlobalEnforceTimeout and GlobalEnforceTimeoutDisabled fields in apidef/api_definitions.go. Corresponding updates are made to the classic JSON schema (apidef/schema.json), OpenAPI (OAS) schemas (apidef/oas/schema/, apidef/mcp/schema/), data migration logic (apidef/migration.go), and validation rules (apidef/validator.go). The OAS mapping logic in apidef/oas/upstream.go is updated to handle the new enforceTimeout object. Extensive unit tests are added to verify schema correctness, validation, and OAS round-tripping.
  • gateway/: The request processing logic is updated. The gateway/reverse_proxy.go module now includes the API-level timeout in its timeout resolution logic by renaming GetHardTimeoutEnforcedSettings to GetEnforcedTimeoutSettings and updating its logic. The middleware in gateway/middleware.go is adjusted to activate timeout enforcement when an API-level timeout is present. A comprehensive integration test suite (TestAPILevelTimeout) is added in gateway/reverse_proxy_test.go to validate the new timeout hierarchy and behavior under various conditions.

Architecture & Impact Assessment

  • What this PR accomplishes: It provides a more flexible and granular timeout configuration model. Users can now define a default timeout for an entire API, which is less tedious than configuring each endpoint individually, while still allowing for endpoint-specific overrides.

  • Key technical changes introduced:

    1. New API Definition Fields: Adds global_enforce_timeout and global_enforce_timeout_disabled to the apidef.VersionInfo struct.
    2. OAS Extension: Introduces the x-tyk-api-gateway.upstream.enforceTimeout object in the OpenAPI specification for managing this setting.
    3. Updated Timeout Prioritization: The gateway's reverse proxy logic is modified to resolve timeouts in the order: Endpoint-level → API-level → Gateway default.
  • Affected system components:

    • Gateway Proxy: The core request-handling path in gateway/reverse_proxy.go is directly modified to implement the new timeout hierarchy.
    • API Definition Handling: The apidef package is updated to handle the new fields during validation, migration, and OAS conversion.
    • External Tooling: Systems that interact with Tyk API definitions, such as the Tyk Dashboard, Management API, and Tyk Operator, will likely require updates to expose and manage these new configuration fields.

Timeout Resolution Flow

The diagram below illustrates how the gateway determines which timeout to apply to an incoming request.

graph TD
    A[Incoming Request] --> B{Check for Endpoint-Level Timeout};
    B --|Yes|--> C[Use Endpoint Timeout];
    B --|No|--> D{Check for API-Level Timeout};
    D --|"Yes (Enabled)"|--> E[Use API-Level Timeout];
    D --|"No / Disabled"|--> F[Use Gateway Default Timeout];
    C --> G[Apply Timeout and Proxy Request];
    E --> G;
    F --> G;
Loading

Scope Discovery & Context Expansion

  • The scope of this PR is well-defined and contained within the Tyk gateway's codebase. The changes are implemented end-to-end, from the data definition layer (apidef) to the runtime enforcement logic (gateway).
  • The central logic change resides in gateway/reverse_proxy.go within the GetEnforcedTimeoutSettings function. This function is called from WrappedServeHTTP for every request, placing it directly in the critical path of request processing.
  • The modification in gateway/middleware.go is a necessary supporting change that ensures the EnforcedTimeoutEnabled flag is set on the API specification at load time if an API-level timeout is configured, which in turn ensures the timeout resolution logic is executed.
  • The addition of extensive integration tests in gateway/reverse_proxy_test.go provides strong confidence that the timeout precedence (endpoint > API > gateway) and fallback mechanisms function correctly. No further code exploration seems necessary to understand the immediate impact.
Metadata
  • Review Effort: 3 / 5
  • Primary Label: feature

Powered by Visor from Probelabs

Last updated: 2026-06-15T11:48:22.488Z | Triggered by: pr_updated | Commit: ed26897

💡 TIP: You can chat with Visor using /visor ask <your question>

@probelabs

probelabs Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Security Issues (1)

Severity Location Issue
🟡 Warning apidef/validator.go:192-199
The API-level timeout validation only checks for negative values and does not enforce an upper limit. An administrator could configure an excessively large timeout (e.g., hours or days), which could lead to resource exhaustion on the gateway by tying up connections for extended periods. This increases the risk of denial-of-service, especially since this setting can apply to all endpoints within an API.
💡 SuggestionIntroduce a configurable upper limit for the timeout value to prevent resource exhaustion from misconfiguration. A sensible default maximum (e.g., 1 hour) could be enforced, with the ability for operators to override it in the gateway's global configuration if a longer timeout is explicitly required.

Security Issues (1)

Severity Location Issue
🟡 Warning apidef/validator.go:192-199
The API-level timeout validation only checks for negative values and does not enforce an upper limit. An administrator could configure an excessively large timeout (e.g., hours or days), which could lead to resource exhaustion on the gateway by tying up connections for extended periods. This increases the risk of denial-of-service, especially since this setting can apply to all endpoints within an API.
💡 SuggestionIntroduce a configurable upper limit for the timeout value to prevent resource exhaustion from misconfiguration. A sensible default maximum (e.g., 1 hour) could be enforced, with the ability for operators to override it in the gateway's global configuration if a longer timeout is explicitly required.
\n\n ### ✅ Architecture Check Passed

No architecture issues found – changes LGTM.

✅ Performance Check Passed

No performance issues found – changes LGTM.

Quality Issues (1)

Severity Location Issue
🟡 Warning apidef/migration_test.go:657
The test for `SetDisabledFlags` only covers the case where `GlobalEnforceTimeout` is not set (is 0). It does not verify that `GlobalEnforceTimeoutDisabled` remains `false` when a timeout value is present. This leaves one branch of the conditional logic added in `apidef/migration.go` untested.
💡 SuggestionAdd a test case to cover the scenario where `GlobalEnforceTimeout` is configured. This will ensure that the `GlobalEnforceTimeoutDisabled` flag is not incorrectly set to `true` when a timeout is specified, fully covering the new logic and preventing potential regressions. A focused test for this new logic would be clearer than adding to the existing large test case.
func TestSetDisabledFlags_GlobalEnforceTimeout(t *testing.T) {
	t.Run(&#34;when timeout is not configured, disabled flag is set&#34;, func(t *testing.T) {
		api := &amp;apidef.APIDefinition{
			VersionData: apidef.VersionData{
				Versions: map[string]apidef.VersionInfo{
					&#34;Default&#34;: {GlobalEnforceTimeout: 0},
				},
			},
		}
		api.SetDisabledFlags()
		assert.True(t, api.VersionData.Versions[&#34;Default&#34;].GlobalEnforceTimeoutDisabled)
	})

	t.Run(&#34;when timeout is configured, disabled flag is not set&#34;, func(t *testing.T) {
		api := &amp;apidef.APIDefinition{
			VersionData: apidef.VersionData{
				Versions: map[string]apidef.VersionInfo{
					&#34;Default&#34;: {GlobalEnforceTimeout: tyktime.ReadableDuration(5 * time.Second)},
				},
			},
		}
		api.SetDisabledFlags()
		assert.False(t, api.VersionData.Versions[&#34;Default&#34;].GlobalEnforceTimeoutDisabled)
	})
}

Powered by Visor from Probelabs

Last updated: 2026-06-15T11:47:43.537Z | Triggered by: pr_updated | Commit: ed26897

💡 TIP: You can chat with Visor using /visor ask <your question>

@vladzabolotnyi

Copy link
Copy Markdown
Contributor Author

/visor

The API-level timeout validation only checks for negative values, but does not enforce an upper limit. An administrator could configure an excessively large timeout (e.g., hours or days), which could lead to resource exhaustion on the gateway by tying up connections for extended periods. This increases the risk of denial-of-service, especially since this setting can apply to all endpoints within an API.

This is intended behavior that described on the latest comments on the ticket

@probelabs

probelabs Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Powered by Visor from Probelabs

Last updated: 2026-06-05T07:35:43.627Z | Triggered by: vladzabolotnyi | Commit: 749796e

💡 TIP: You can chat with Visor using /visor ask <your question>

@imogenkraak imogenkraak left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@bojank93 bojank93 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@vladzabolotnyi
vladzabolotnyi enabled auto-merge (squash) June 11, 2026 12:34
@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

🎯 Recommended Merge Targets

Based on JIRA ticket TT-15813: [BE] Feature Request: API-Level Timeout Configuration

Fix Version: Tyk 5.14.0

⚠️ Warning: Expected release branches not found in repository

Required:

  • master - No matching release branches found. Fix will be included in future releases.

📋 Workflow

  1. Merge this PR to master first

@vladzabolotnyi
vladzabolotnyi disabled auto-merge June 11, 2026 12:38
@vladzabolotnyi
vladzabolotnyi enabled auto-merge (squash) June 15, 2026 11:27
@sentinelone-cnapp-eu1

Copy link
Copy Markdown

SentinelOne CNS Hardcoded Secret Detector
✅ Congratulations, your code is safe

SentinelOne CNS is a cloud-agnostic, agentless CSPM & CWPP solution that continuously detects and prevents vulnerabilities that have the highest probability of being exploited in Azure, AWS, Google Cloud, and Kubernetes.

@github-actions

Copy link
Copy Markdown
Contributor

🚨 Jira Linter Failed

Commit: ed26897
Failed at: 2026-06-15 11:46:11 UTC

The Jira linter failed to validate your PR. Please check the error details below:

🔍 Click to view error details
failed to get Jira issue: failed to fetch Jira issue TT-15813: Issue does not exist or you do not have permission to see it.: request failed. Please analyze the request body for more details. Status code: 404

Next Steps

  • Ensure your branch name contains a valid Jira ticket ID (e.g., ABC-123)
  • Verify your PR title matches the branch's Jira ticket ID
  • Check that the Jira ticket exists and is accessible

This comment will be automatically deleted once the linter passes.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
100.0% Coverage on New Code
0.0% Duplication on New Code

See analysis details on SonarQube Cloud

@vladzabolotnyi
vladzabolotnyi merged commit 1c6e0e8 into master Jun 15, 2026
53 of 56 checks passed
@vladzabolotnyi
vladzabolotnyi deleted the TT-15813 branch June 15, 2026 13:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants