feat: use redis to fix state sync issues
This commit is contained in:
parent
188aadf638
commit
6027c8271d
|
@ -1,3 +1,4 @@
|
|||
SIGN_KEY=
|
||||
DEBUG=0
|
||||
MAIN_REDIRECT=https://github.com/shiftinv/github-webhook-filter
|
||||
REDIS_URL=
|
||||
|
|
2
deps.ts
2
deps.ts
|
@ -1,4 +1,4 @@
|
|||
export * as http from "https://deno.land/std@0.154.0/http/mod.ts";
|
||||
export * as log from "https://deno.land/std@0.154.0/log/mod.ts";
|
||||
export * as hex from "https://deno.land/std@0.154.0/encoding/hex.ts";
|
||||
export { default as TTL } from "https://deno.land/x/ttl@1.0.1/mod.ts";
|
||||
export * as redis from "https://deno.land/x/redis@v0.27.0/mod.ts";
|
||||
|
|
|
@ -17,6 +17,7 @@ export default {
|
|||
maxWebhookRetries: parseInt(get("MAX_RETRIES", "3")),
|
||||
maxWebhookRetryMs: parseInt(get("MAX_RETRY_MS", "30000")),
|
||||
mainRedirect: get("MAIN_REDIRECT", null),
|
||||
redisUrl: get("REDIS_URL"),
|
||||
|
||||
// set by deno deploy
|
||||
deployId: get("DENO_DEPLOYMENT_ID", "<unknown>"),
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { TTL } from "../deps.ts";
|
||||
import { reviewCommentManager } from "./manager.ts";
|
||||
import { UrlConfig } from "./types.d.ts";
|
||||
import { requestLog } from "./util.ts";
|
||||
|
||||
const reviewComments = new TTL<number>(2 * 1000);
|
||||
|
||||
export default function filter(headers: Headers, json: any, config: UrlConfig): string | null {
|
||||
export default async function filter(
|
||||
headers: Headers,
|
||||
json: any,
|
||||
config: UrlConfig,
|
||||
): Promise<string | null> {
|
||||
const reqLog = requestLog(headers);
|
||||
const event = headers.get("x-github-event") || "unknown";
|
||||
const login: string | undefined = json.sender?.login?.toLowerCase();
|
||||
|
@ -47,14 +49,11 @@ export default function filter(headers: Headers, json: any, config: UrlConfig):
|
|||
if (config.commentBurstLimit && reviewId) {
|
||||
const cacheKey = `${reviewId}-${login}`;
|
||||
reqLog.debug(`filter: checking cache key ${cacheKey}`);
|
||||
reqLog.debug(
|
||||
`filter: full comment cache ${JSON.stringify(Array.from(reviewComments))}`,
|
||||
);
|
||||
const curr = reviewComments.get(cacheKey);
|
||||
const curr = await reviewCommentManager.getAndIncrement(cacheKey);
|
||||
reqLog.debug(`filter: current value: ${curr}`);
|
||||
if (curr && curr >= config.commentBurstLimit) {
|
||||
return `exceeded comment burst limit (${config.commentBurstLimit}) for review ${reviewId}`;
|
||||
}
|
||||
reviewComments.set(cacheKey, (curr ?? 0) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ export default async function handle(
|
|||
const json = JSON.parse(data);
|
||||
|
||||
// do the thing
|
||||
const filterReason = filterWebhook(req.headers, json, urlConfig);
|
||||
const filterReason = await filterWebhook(req.headers, json, urlConfig);
|
||||
if (filterReason !== null) {
|
||||
const reqLog = requestLog(req.headers);
|
||||
reqLog.debug(`handler: ignored due to '${filterReason}'`);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
import { redis } from "../deps.ts";
|
||||
import config from "./config.ts";
|
||||
|
||||
class ReviewCommentManager {
|
||||
private redis: redis.Redis;
|
||||
constructor() {
|
||||
this.redis = redis.createLazyClient({
|
||||
...redis.parseURL(config.redisUrl),
|
||||
maxRetryCount: 3,
|
||||
});
|
||||
}
|
||||
|
||||
async getAndIncrement(key: string): Promise<number> {
|
||||
if (!this.redis.isConnected) {
|
||||
// seems like pipelines don't quite work with the lazy client
|
||||
await this.redis.ping();
|
||||
}
|
||||
const pl = this.redis.pipeline();
|
||||
pl.incr(`reviewcomment:${key}`);
|
||||
pl.expire(`reviewcomment:${key}`, 3);
|
||||
const results = await pl.flush();
|
||||
|
||||
const newValue = results[0] as number;
|
||||
return newValue - 1; // return old value
|
||||
}
|
||||
}
|
||||
|
||||
export const reviewCommentManager = new ReviewCommentManager();
|
Loading…
Reference in New Issue