Skip to content

Commit 9213f52

Browse files
authored
Merge pull request #1163 from Portkey-AI/feat/circuit_breaker
feat: base integration for circuit breaker
2 parents a2c9f03 + c06b42e commit 9213f52

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

src/handlers/handlerUtils.ts

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,7 @@ export async function tryTargetsRecursively(
598598

599599
// start: merge inherited config with current target config (preference given to current)
600600
const currentInheritedConfig: Record<string, any> = {
601+
id: inheritedConfig.id || currentTarget.id,
601602
overrideParams: {
602603
...inheritedConfig.overrideParams,
603604
...currentTarget.overrideParams,
@@ -751,19 +752,34 @@ export async function tryTargetsRecursively(
751752
];
752753
// end: merge inherited config with current target config (preference given to current)
753754

755+
const isHandlingCircuitBreaker = currentInheritedConfig.id;
756+
if (isHandlingCircuitBreaker) {
757+
const healthyTargets = (currentTarget.targets || [])
758+
.map((t: any, index: number) => ({
759+
...t,
760+
originalIndex: index,
761+
}))
762+
.filter((t: any) => !t.isOpen);
763+
764+
if (healthyTargets.length) {
765+
currentTarget.targets = healthyTargets;
766+
}
767+
}
768+
754769
let response;
755770

756771
switch (strategyMode) {
757772
case StrategyModes.FALLBACK:
758773
for (const [index, target] of currentTarget.targets.entries()) {
774+
const originalIndex = target.originalIndex || index;
759775
response = await tryTargetsRecursively(
760776
c,
761777
target,
762778
request,
763779
requestHeaders,
764780
fn,
765781
method,
766-
`${currentJsonPath}.targets[${index}]`,
782+
`${currentJsonPath}.targets[${originalIndex}]`,
767783
currentInheritedConfig
768784
);
769785
if (response?.headers.get('x-portkey-gateway-exception') === 'true') {
@@ -791,8 +807,9 @@ export async function tryTargetsRecursively(
791807

792808
let randomWeight = Math.random() * totalWeight;
793809
for (const [index, provider] of currentTarget.targets.entries()) {
810+
const originalIndex = provider.originalIndex || index;
794811
if (randomWeight < provider.weight) {
795-
currentJsonPath = currentJsonPath + `.targets[${index}]`;
812+
currentJsonPath = currentJsonPath + `.targets[${originalIndex}]`;
796813
response = await tryTargetsRecursively(
797814
c,
798815
provider,
@@ -836,28 +853,30 @@ export async function tryTargetsRecursively(
836853
throw new RouterError(conditionalRouter.message);
837854
}
838855

856+
const originalIndex = finalTarget.originalIndex || finalTarget.index;
839857
response = await tryTargetsRecursively(
840858
c,
841859
finalTarget,
842860
request,
843861
requestHeaders,
844862
fn,
845863
method,
846-
`${currentJsonPath}.targets[${finalTarget.index}]`,
864+
`${currentJsonPath}.targets[${originalIndex}]`,
847865
currentInheritedConfig
848866
);
849867
break;
850868
}
851869

852870
case StrategyModes.SINGLE:
871+
const originalIndex = currentTarget.targets[0].originalIndex || 0;
853872
response = await tryTargetsRecursively(
854873
c,
855874
currentTarget.targets[0],
856875
request,
857876
requestHeaders,
858877
fn,
859878
method,
860-
`${currentJsonPath}.targets[0]`,
879+
`${currentJsonPath}.targets[${originalIndex}]`,
861880
currentInheritedConfig
862881
);
863882
break;
@@ -873,6 +892,15 @@ export async function tryTargetsRecursively(
873892
currentJsonPath,
874893
method
875894
);
895+
if (isHandlingCircuitBreaker) {
896+
await c.get('handleCircuitBreakerResponse')?.(
897+
response,
898+
currentInheritedConfig.id,
899+
currentTarget.cbConfig,
900+
currentJsonPath,
901+
c
902+
);
903+
}
876904
} catch (error: any) {
877905
// tryPost always returns a Response.
878906
// TypeError will check for all unhandled exceptions.
@@ -898,6 +926,15 @@ export async function tryTargetsRecursively(
898926
);
899927
} else {
900928
response = error.response;
929+
if (isHandlingCircuitBreaker) {
930+
await c.get('recordCircuitBreakerFailure')?.(
931+
env(c),
932+
currentInheritedConfig.id,
933+
currentTarget.cbConfig,
934+
currentJsonPath,
935+
response.status
936+
);
937+
}
901938
}
902939
}
903940
break;
@@ -1207,6 +1244,7 @@ export function constructConfigFromRequestHeaders(
12071244
'output_guardrails',
12081245
'default_input_guardrails',
12091246
'default_output_guardrails',
1247+
'cb_config',
12101248
]) as any;
12111249
}
12121250

src/types/requestBody.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ export interface Targets {
197197

198198
defaultInputGuardrails?: HookObject[];
199199
defaultOutputGuardrails?: HookObject[];
200+
originalIndex?: number;
200201
}
201202

202203
/**

0 commit comments

Comments
 (0)