Manage throttling policies¶
What happens
An admin creates or edits rate-limit policies (also called tiers) in the Admin Portal. There are four families, one for each level at which a limit applies. Resource-level policies can also have conditional groups, e.g. "a higher limit for requests from this IP range".
Who: Admin (Admin Portal) · Tables written: AM_POLICY_SUBSCRIPTION, AM_POLICY_APPLICATION, AM_API_THROTTLE_POLICY + AM_CONDITION_GROUP + condition tables, AM_POLICY_GLOBAL, AM_BLOCK_CONDITIONS, AM_THROTTLE_TIER_PERMISSIONS · Tables read: none
The four policy families¶
Each family limits traffic at a different level.
flowchart LR
S[Subscription tier] --> SUB[AM_SUBSCRIPTION.TIER_ID]
A[Application tier] --> APP[AM_APPLICATION.APPLICATION_TIER]
R[Resource tier] --> URL[AM_API_URL_MAPPING.THROTTLING_TIER]
G[Custom / global policy] --> ALL[All traffic matching a key template]
- The first three are attached by name. The custom policy applies globally through its
KEY_TEMPLATE. - Blocking conditions sit beside these and deny traffic outright, e.g. by IP, user, application or API context.
The flow at a glance¶
This diagram shows an admin creating a resource tier with one conditional group.
sequenceDiagram
actor Admin
participant AP as Admin Portal
participant DB as APIM DB
participant TM as Traffic Manager
Admin->>AP: Create advanced tier "PizzaAdvanced"
AP->>DB: insert AM_API_THROTTLE_POLICY
AP->>DB: insert AM_CONDITION_GROUP
AP->>DB: insert AM_IP_CONDITION / header / query / JWT-claim rows
AP-->>TM: push policy to Traffic Manager
AP-->>Admin: Policy saved
Step by step¶
-
Subscription tier, e.g. Gold. One row in
AM_POLICY_SUBSCRIPTION, unique on(NAME, TENANT_ID).QUOTA_TYPEis the discriminator:requestCount,bandwidthVolume,eventCountoraiApiQuota. It decides which columns matter.QUOTA+UNIT_TIME+TIME_UNITgive the limit, e.g. 5000 per 1 min.RATE_LIMIT_COUNT/RATE_LIMIT_TIME_UNITset a burst limit.STOP_ON_QUOTA_REACHdecides whether requests are refused or only flagged when the quota runs out.BILLING_PLAN(FREE,COMMERCIAL) and the monetization columns cover paid plans.MAX_COMPLEXITY/MAX_DEPTHapply to GraphQL, andTOTAL_TOKEN_COUNT/PROMPT_TOKEN_COUNT/COMPLETION_TOKEN_COUNTto AI APIs.
NAME QUOTA_TYPE QUOTA UNIT_TIME TIME_UNIT STOP_ON_QUOTA_REACH BILLING_PLAN TENANT_ID Gold requestCount 5000 1 min true FREE -1234 PizzaSubTier requestCount 1000 1 min true FREE -1234 -
Application tier, e.g. 10PerMin. One row in
AM_POLICY_APPLICATION, with the same quota columns but none of the billing ones. It limits the total traffic of an application across all its subscriptions. -
Resource tier with conditions. This one has a small tree:
AM_API_THROTTLE_POLICYholds the default limit (DEFAULT_QUOTA_TYPE,DEFAULT_QUOTA, …) andAPPLICABLE_LEVEL(apiLevelorresourceLevel).- Each
AM_CONDITION_GROUProw hasPOLICY_IDas an FK with cascade, plus its own quota that applies when its conditions match. - Each group has any number of conditions, all FKs with cascade:
AM_IP_CONDITION,AM_HEADER_FIELD_CONDITION,AM_QUERY_PARAMETER_CONDITIONandAM_JWT_CLAIM_CONDITION. TheirIS_*_MAPPINGflags invert the match ("NOT equal").
erDiagram AM_API_THROTTLE_POLICY ||--o{ AM_CONDITION_GROUP : "has" AM_CONDITION_GROUP ||--o{ AM_IP_CONDITION : "if IP" AM_CONDITION_GROUP ||--o{ AM_HEADER_FIELD_CONDITION : "if header" AM_CONDITION_GROUP ||--o{ AM_QUERY_PARAMETER_CONDITION : "if query param" AM_CONDITION_GROUP ||--o{ AM_JWT_CLAIM_CONDITION : "if JWT claim"Table Example row AM_API_THROTTLE_POLICY POLICY_ID 5, NAME PizzaAdvanced, DEFAULT_QUOTA 10 per 1 min, APPLICABLE_LEVELapiLevelAM_CONDITION_GROUP CONDITION_GROUP_ID 1, POLICY_ID 5, QUOTA 2 per 1 min, DESCRIPTION mobile clientsAM_HEADER_FIELD_CONDITION CONDITION_GROUP_ID 1, HEADER_FIELD_NAME User-Agent, HEADER_FIELD_VALUEmobileAM_IP_CONDITION CONDITION_GROUP_ID 1, SPECIFIC_IP 10.0.0.1, WITHIN_IP_RANGE false -
Custom (global) policy. One row in
AM_POLICY_GLOBALwith aKEY_TEMPLATE, e.g.$userId, and the policy logic as a Siddhi query in theSIDDHI_QUERYblob. -
Blocking condition. One row in
AM_BLOCK_CONDITIONS, withTYPEset toAPI,APPLICATION,USER,IPorIPRANGE, plusBLOCK_CONDITION(the value),ENABLEDandDOMAIN(the tenant).CONDITION_ID TYPE BLOCK_CONDITION ENABLED DOMAIN 1 IP {"invert":false,"fixedIp":"10.9.9.9"}true carbon.super -
Who may use a tier (optional). Creating a subscription tier with a role restriction wrote
AM_THROTTLE_TIER_PERMISSIONS(TIER = 'PizzaSubTier',PERMISSIONS_TYPE = 'allow',ROLES = 'admin',TENANT_ID). The olderAM_TIER_PERMISSIONShas the same shape but wasn't written. -
Deploy. The policy is pushed to the Traffic Manager and gateways by event. The
IS_DEPLOYEDcolumn exists, but it stayed0on every policy created in the test, so don't use it to tell whether a policy is live.AM_POLICY_HARD_THROTTLINGis a legacy table for backend hard limits.
Logical links (no foreign key)
Policies are referenced by name from AM_SUBSCRIPTION.TIER_ID, AM_APPLICATION.APPLICATION_TIER, AM_API_URL_MAPPING.THROTTLING_TIER and AM_API.API_TIER. There are no FKs, so renaming a policy isn't possible, and deleting one that's in use is blocked in code.
What gets cleaned up¶
- Deleting a resource tier cascades to its condition groups and all their conditions.
- The other policy tables have no children in the database.
Try it¶
This query shows each resource tier with its conditional groups and IP conditions.
SELECT p.NAME, p.DEFAULT_QUOTA, p.DEFAULT_TIME_UNIT,
g.CONDITION_GROUP_ID, g.QUOTA AS GROUP_QUOTA,
ip.SPECIFIC_IP, ip.STARTING_IP, ip.ENDING_IP
FROM AM_API_THROTTLE_POLICY p
LEFT JOIN AM_CONDITION_GROUP g ON g.POLICY_ID = p.POLICY_ID
LEFT JOIN AM_IP_CONDITION ip ON ip.CONDITION_GROUP_ID = g.CONDITION_GROUP_ID
ORDER BY p.NAME;
Different in 3.x
3.x has the same policy tables. Its AM_POLICY_SUBSCRIPTION lacks CONNECTIONS_COUNT and the AI token-count columns (TOTAL_TOKEN_COUNT, PROMPT_TOKEN_COUNT, COMPLETION_TOKEN_COUNT). See 3.x: Manage throttling policies.
Related domains: Throttling policies · Applications & subscriptions