Skip to content

Commit

Permalink
Fix S3 clock skew and tighten 5xx alerts (#392)
Browse files Browse the repository at this point in the history
* Tighten 5xx alerts

* Do not use the S3 client in the injector
  • Loading branch information
codyborn authored Dec 2, 2024
1 parent 8788bec commit a417183
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 20 deletions.
8 changes: 4 additions & 4 deletions bin/stacks/api-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -440,10 +440,10 @@ export class APIStack extends cdk.Stack {
alarmName: 'UniswapXParameterizationAPI-SEV2-5XX',
metric: api.metricServerError({
period: Duration.minutes(5),
// For this metric 'avg' represents error rate.
statistic: 'avg',
// For this metric 'sum' represents error count.
statistic: 'sum',
}),
threshold: 0.5,
threshold: 100,
// Beta has much less traffic so is more susceptible to transient errors.
evaluationPeriods: stage == STAGE.BETA ? 5 : 3,
});
Expand All @@ -455,7 +455,7 @@ export class APIStack extends cdk.Stack {
// For this metric 'sum' represents error count.
statistic: 'sum',
}),
threshold: 100,
threshold: 20,
// Beta has much less traffic so is more susceptible to transient errors.
evaluationPeriods: stage == STAGE.BETA ? 5 : 3,
});
Expand Down
6 changes: 1 addition & 5 deletions lib/handlers/hard-quote/injector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,7 @@ export class QuoteInjector extends ApiInjector<ContainerInjected, RequestInjecte
const orderServiceUrl = checkDefined(process.env.ORDER_SERVICE_URL, 'ORDER_SERVICE_URL is not defined');

const webhookProvider = new S3WebhookConfigurationProvider(log, `${WEBHOOK_CONFIG_BUCKET}-${stage}-1`, s3Key);
await webhookProvider.fetchEndpoints();
const circuitBreakerProvider = new DynamoCircuitBreakerConfigurationProvider(
log,
webhookProvider.fillerEndpoints()
);
const circuitBreakerProvider = new DynamoCircuitBreakerConfigurationProvider(log, webhookProvider);

const orderServiceProvider = new UniswapXServiceProvider(log, orderServiceUrl);

Expand Down
6 changes: 1 addition & 5 deletions lib/handlers/quote/injector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,7 @@ export class QuoteInjector extends ApiInjector<ContainerInjected, RequestInjecte
const s3Key = stage === STAGE.BETA ? BETA_S3_KEY : PRODUCTION_S3_KEY;

const webhookProvider = new S3WebhookConfigurationProvider(log, `${WEBHOOK_CONFIG_BUCKET}-${stage}-1`, s3Key);
await webhookProvider.fetchEndpoints();
const circuitBreakerProvider = new DynamoCircuitBreakerConfigurationProvider(
log,
webhookProvider.fillerEndpoints()
);
const circuitBreakerProvider = new DynamoCircuitBreakerConfigurationProvider(log, webhookProvider);

const complianceKey = stage === STAGE.BETA ? BETA_COMPLIANCE_S3_KEY : PROD_COMPLIANCE_S3_KEY;
const fillerComplianceProvider = new S3FillerComplianceConfigurationProvider(
Expand Down
21 changes: 15 additions & 6 deletions lib/providers/circuit-breaker/dynamo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ import Logger from 'bunyan';

import { CircuitBreakerConfigurationProvider, EndpointStatuses } from '.';
import { BaseTimestampRepository, FillerTimestampMap, TimestampRepository } from '../../repositories';
import { WebhookConfiguration } from '../webhook';
import { S3WebhookConfigurationProvider, WebhookConfiguration } from '../webhook';

export class DynamoCircuitBreakerConfigurationProvider implements CircuitBreakerConfigurationProvider {
private log: Logger;
private fillerEndpoints: string[];
private webhookProvider: S3WebhookConfigurationProvider;
private fillerEndpoints: string[] = [];
private lastUpdatedTimestamp: number;
private timestampDB: BaseTimestampRepository;
private timestamps: FillerTimestampMap = new Map();

// try to refetch endpoints every 30 seconds
private static UPDATE_PERIOD_MS = 1 * 30000;

constructor(_log: Logger, _fillerEndpoints: string[] = []) {
constructor(_log: Logger, _webhookProvider: S3WebhookConfigurationProvider) {
this.log = _log.child({ quoter: 'CircuitBreakerConfigurationProvider' });
this.fillerEndpoints = _fillerEndpoints;
this.webhookProvider = _webhookProvider;
this.lastUpdatedTimestamp = Date.now();
const documentClient = DynamoDBDocumentClient.from(new DynamoDBClient({}), {
marshallOptions: {
Expand All @@ -31,9 +32,17 @@ export class DynamoCircuitBreakerConfigurationProvider implements CircuitBreaker
this.timestampDB = TimestampRepository.create(documentClient);
}

private async getFillerEndpoints(): Promise<string[]> {
if (this.fillerEndpoints.length === 0) {
this.fillerEndpoints = this.webhookProvider.fillerEndpoints();
this.lastUpdatedTimestamp = Date.now();
}
return this.fillerEndpoints;
}

async getConfigurations(): Promise<FillerTimestampMap> {
if (
this.fillerEndpoints.length === 0 ||
(await this.getFillerEndpoints()).length === 0 ||
Date.now() - this.lastUpdatedTimestamp > DynamoCircuitBreakerConfigurationProvider.UPDATE_PERIOD_MS
) {
await this.fetchConfigurations();
Expand All @@ -44,7 +53,7 @@ export class DynamoCircuitBreakerConfigurationProvider implements CircuitBreaker
}

async fetchConfigurations(): Promise<void> {
this.timestamps = await this.timestampDB.getFillerTimestampsMap(this.fillerEndpoints);
this.timestamps = await this.timestampDB.getFillerTimestampsMap(await this.getFillerEndpoints());
}

/* add filler to `enabled` array if it's not blocked until a future timestamp;
Expand Down

0 comments on commit a417183

Please sign in to comment.