feat: retry AniList "update watch status" request if it fails
This commit is contained in:
@@ -3,4 +3,5 @@ preload = [
|
|||||||
"./testSetup.ts",
|
"./testSetup.ts",
|
||||||
"./src/mocks/consumet.ts",
|
"./src/mocks/consumet.ts",
|
||||||
"./src/mocks/getGoogleAuthToken.ts",
|
"./src/mocks/getGoogleAuthToken.ts",
|
||||||
|
"./src/mocks/qstash.ts",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
|
import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
|
||||||
import { env } from "hono/adapter";
|
import { env } from "hono/adapter";
|
||||||
|
|
||||||
|
import { verifyQstashHeader } from "~/libs/qstash/verifyQstashHeader";
|
||||||
|
import { readEnvVariable } from "~/libs/readEnvVariable";
|
||||||
import { setWatchStatus } from "~/models/watchStatus";
|
import { setWatchStatus } from "~/models/watchStatus";
|
||||||
import type { Env } from "~/types/env";
|
import type { Env } from "~/types/env";
|
||||||
import {
|
import {
|
||||||
@@ -70,7 +72,18 @@ app.openapi(route, async (c) => {
|
|||||||
} = await c.req.json<typeof UpdateWatchStatusRequest._type>();
|
} = await c.req.json<typeof UpdateWatchStatusRequest._type>();
|
||||||
const aniListToken = c.req.header("X-AniList-Token");
|
const aniListToken = c.req.header("X-AniList-Token");
|
||||||
|
|
||||||
if (!isRetrying) {
|
if (isRetrying) {
|
||||||
|
if (
|
||||||
|
!(await verifyQstashHeader(
|
||||||
|
env<Env, typeof c>(c, "workerd"),
|
||||||
|
c.req.path,
|
||||||
|
c.req.header("Upstash-Signature"),
|
||||||
|
await c.req.text(),
|
||||||
|
))
|
||||||
|
) {
|
||||||
|
return c.json(ErrorResponse, { status: 401 });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
try {
|
try {
|
||||||
const { wasAdded, wasDeleted } = await setWatchStatus(
|
const { wasAdded, wasDeleted } = await setWatchStatus(
|
||||||
env<Env, typeof c>(c, "workerd"),
|
env<Env, typeof c>(c, "workerd"),
|
||||||
@@ -95,6 +108,19 @@ app.openapi(route, async (c) => {
|
|||||||
console.error(
|
console.error(
|
||||||
new Error("Failed to update watch status on Anilist", { cause: error }),
|
new Error("Failed to update watch status on Anilist", { cause: error }),
|
||||||
);
|
);
|
||||||
|
await import("@upstash/qstash")
|
||||||
|
.then(
|
||||||
|
({ Client }) =>
|
||||||
|
new Client({ token: readEnvVariable(c.env, "QSTASH_TOKEN") }),
|
||||||
|
)
|
||||||
|
.then((client) =>
|
||||||
|
client.publishJSON({
|
||||||
|
url: c.req.url,
|
||||||
|
body: { deviceId, watchStatus, titleId, isRetrying: true },
|
||||||
|
retries: 0,
|
||||||
|
delay: 60,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.json(SuccessResponse, { status: 200 });
|
return c.json(SuccessResponse, { status: 200 });
|
||||||
|
|||||||
18
src/mocks/qstash.ts
Normal file
18
src/mocks/qstash.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { SignatureError } from "@upstash/qstash";
|
||||||
|
|
||||||
|
import { mock } from "bun:test";
|
||||||
|
|
||||||
|
class MockQstashClient {
|
||||||
|
batchJSON = mock();
|
||||||
|
publishJSON = mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockQstashReceiver {
|
||||||
|
verify = mock();
|
||||||
|
}
|
||||||
|
|
||||||
|
mock.module("@upstash/qstash", () => ({
|
||||||
|
Client: MockQstashClient,
|
||||||
|
Receiver: MockQstashReceiver,
|
||||||
|
SignatureError,
|
||||||
|
}));
|
||||||
@@ -19,7 +19,7 @@ export function setWatchStatus(
|
|||||||
watchStatus: (typeof WatchStatusValues)[number] | null,
|
watchStatus: (typeof WatchStatusValues)[number] | null,
|
||||||
) {
|
) {
|
||||||
let dbAction;
|
let dbAction;
|
||||||
const isSavingTitle = watchStatus === "CURRENT";
|
const isSavingTitle = watchStatus === "CURRENT" || watchStatus === "PLANNING";
|
||||||
if (isSavingTitle) {
|
if (isSavingTitle) {
|
||||||
dbAction = saveTitle(env, deviceId, titleId);
|
dbAction = saveTitle(env, deviceId, titleId);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user