mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-11-26 08:15:07 -05:00
Properly handle spans of image downloading (#1176)
This commit is contained in:
commit
f59cb5d671
1
.github/workflows/api-test.yml
vendored
1
.github/workflows/api-test.yml
vendored
@ -37,3 +37,4 @@ jobs:
|
||||
run: bun test
|
||||
env:
|
||||
PGHOST: localhost
|
||||
IMAGES_PATH: ./images
|
||||
|
||||
@ -73,7 +73,7 @@ export const auth = new Elysia({ name: "auth" })
|
||||
.macro({
|
||||
permissions(perms: string[]) {
|
||||
return {
|
||||
beforeHandle: ({ jwt, status }) => {
|
||||
beforeHandle: function permissionCheck({ jwt, status }) {
|
||||
for (const perm of perms) {
|
||||
if (!jwt!.permissions.includes(perm)) {
|
||||
return status(403, {
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import path from "node:path";
|
||||
import { getCurrentSpan, record, setAttributes } from "@elysiajs/opentelemetry";
|
||||
import { SpanStatusCode } from "@opentelemetry/api";
|
||||
import { encode } from "blurhash";
|
||||
import { and, eq, is, lt, type SQL, sql } from "drizzle-orm";
|
||||
import { PgColumn, type PgTable } from "drizzle-orm/pg-core";
|
||||
@ -78,44 +80,7 @@ export const enqueueOptImage = async (
|
||||
};
|
||||
|
||||
export const processImages = async () => {
|
||||
async function processOne() {
|
||||
return await db.transaction(async (tx) => {
|
||||
const [item] = await tx
|
||||
.select()
|
||||
.from(mqueue)
|
||||
.for("update", { skipLocked: true })
|
||||
.where(and(eq(mqueue.kind, "image"), lt(mqueue.attempt, 5)))
|
||||
.orderBy(mqueue.attempt, mqueue.createdAt)
|
||||
.limit(1);
|
||||
|
||||
if (!item) return false;
|
||||
|
||||
const img = item.message as ImageTask;
|
||||
try {
|
||||
const blurhash = await downloadImage(img.id, img.url);
|
||||
const ret: Image = { id: img.id, source: img.url, blurhash };
|
||||
|
||||
const table = sql.raw(img.table);
|
||||
const column = sql.raw(img.column);
|
||||
|
||||
await tx.execute(sql`
|
||||
update ${table} set ${column} = ${ret}
|
||||
where ${column}->'id' = ${sql.raw(`'"${img.id}"'::jsonb`)}
|
||||
`);
|
||||
|
||||
await tx.delete(mqueue).where(eq(mqueue.id, item.id));
|
||||
} catch (err: any) {
|
||||
console.error("Failed to download image", img.url, err.message);
|
||||
// don't use the transaction here, it can be aborted.
|
||||
await db
|
||||
.update(mqueue)
|
||||
.set({ attempt: sql`${mqueue.attempt}+1` })
|
||||
.where(eq(mqueue.id, item.id));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return record("download images", async () => {
|
||||
let running = false;
|
||||
async function processAll() {
|
||||
if (running) return;
|
||||
@ -138,8 +103,55 @@ export const processImages = async () => {
|
||||
// start processing old tasks
|
||||
await processAll();
|
||||
return () => client.release(true);
|
||||
});
|
||||
};
|
||||
|
||||
async function processOne() {
|
||||
return record("download", async () => {
|
||||
return await db.transaction(async (tx) => {
|
||||
const [item] = await tx
|
||||
.select()
|
||||
.from(mqueue)
|
||||
.for("update", { skipLocked: true })
|
||||
.where(and(eq(mqueue.kind, "image"), lt(mqueue.attempt, 5)))
|
||||
.orderBy(mqueue.attempt, mqueue.createdAt)
|
||||
.limit(1);
|
||||
|
||||
if (!item) return false;
|
||||
|
||||
const img = item.message as ImageTask;
|
||||
setAttributes({ "item.url": img.url });
|
||||
try {
|
||||
const blurhash = await downloadImage(img.id, img.url);
|
||||
const ret: Image = { id: img.id, source: img.url, blurhash };
|
||||
|
||||
const table = sql.raw(img.table);
|
||||
const column = sql.raw(img.column);
|
||||
|
||||
await tx.execute(sql`
|
||||
update ${table} set ${column} = ${ret}
|
||||
where ${column}->'id' = ${sql.raw(`'"${img.id}"'::jsonb`)}
|
||||
`);
|
||||
|
||||
await tx.delete(mqueue).where(eq(mqueue.id, item.id));
|
||||
} catch (err: any) {
|
||||
const span = getCurrentSpan();
|
||||
if (span) {
|
||||
span.recordException(err);
|
||||
span.setStatus({ code: SpanStatusCode.ERROR });
|
||||
}
|
||||
console.error("Failed to download image", img.url, err.message);
|
||||
// don't use the transaction here, it can be aborted.
|
||||
await db
|
||||
.update(mqueue)
|
||||
.set({ attempt: sql`${mqueue.attempt}+1` })
|
||||
.where(eq(mqueue.id, item.id));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function downloadImage(id: string, url: string): Promise<string> {
|
||||
const low = await getFile(path.join(imageDir, `${id}.low.jpg`))
|
||||
.arrayBuffer()
|
||||
|
||||
@ -429,6 +429,8 @@ traefikproxy:
|
||||
extraArgs:
|
||||
- '--entryPoints.web.address=:80/tcp'
|
||||
- '--entryPoints.websecure.address=:443/tcp'
|
||||
- '--entryPoints.web.forwardedHeaders.insecure=true'
|
||||
- '--entryPoints.websecure.forwardedHeaders.insecure=true'
|
||||
- '--api.dashboard=true'
|
||||
- '--api.insecure=true'
|
||||
- '--log.level=INFO'
|
||||
|
||||
@ -101,6 +101,7 @@ class RequestProcessor:
|
||||
finally:
|
||||
self._processing = False
|
||||
|
||||
@tracer.start_as_current_span("process video")
|
||||
async def process_request(self):
|
||||
cur = await self._database.fetchrow(
|
||||
"""
|
||||
@ -128,7 +129,8 @@ class RequestProcessor:
|
||||
return False
|
||||
request = Request.model_validate(cur)
|
||||
|
||||
with tracer.start_as_current_span(f"process {request.title}") as span:
|
||||
span = trace.get_current_span()
|
||||
span.update_name(f"process {request.title}")
|
||||
logger.info(f"Starting to process {request.title}")
|
||||
try:
|
||||
show = await self._run_request(request)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user