refactored EventManager to run asyncs on call only, app defaults to run before response (#129)

* refactored EventManager to run asyncs on call only, app defaults to run before response

* fix tests
This commit is contained in:
dswbx
2025-04-01 11:19:55 +02:00
committed by GitHub
parent 434d56672c
commit 36e4224b33
11 changed files with 244 additions and 64 deletions

View File

@@ -9,6 +9,7 @@ import { getBinding } from "./bindings";
import { getCached } from "./modes/cached";
import { getDurable } from "./modes/durable";
import { getFresh, getWarm } from "./modes/fresh";
import type { CreateAppConfig } from "App";
export type CloudflareBkndConfig<Env = any> = FrameworkBkndConfig<Context<Env>> & {
mode?: "warm" | "fresh" | "cache" | "durable";
@@ -32,8 +33,14 @@ export type Context<Env = any> = {
ctx: ExecutionContext;
};
export const constants = {
exec_async_event_id: "cf_register_waituntil",
cache_endpoint: "/__bknd/cache",
do_endpoint: "/__bknd/do",
};
let media_registered: boolean = false;
export function makeCfConfig(config: CloudflareBkndConfig, context: Context) {
export function makeCfConfig(config: CloudflareBkndConfig, context: Context): CreateAppConfig {
if (!media_registered) {
registerMedia(context.env as any);
media_registered = true;
@@ -61,7 +68,14 @@ export function makeCfConfig(config: CloudflareBkndConfig, context: Context) {
}
}
return appConfig;
return {
...appConfig,
options: {
...appConfig.options,
// if not specified explicitly, disable it to use ExecutionContext's waitUntil
asyncEventsMode: config.options?.asyncEventsMode ?? "none",
},
};
}
export function serve<Env = any>(config: CloudflareBkndConfig<Env> = {}) {

View File

@@ -1,6 +1,6 @@
import { App } from "bknd";
import { createRuntimeApp } from "bknd/adapter";
import { type CloudflareBkndConfig, type Context, makeCfConfig } from "../index";
import { type CloudflareBkndConfig, constants, type Context, makeCfConfig } from "../index";
export async function getCached(config: CloudflareBkndConfig, { env, ctx, ...args }: Context) {
const { kv } = config.bindings?.(env)!;
@@ -19,13 +19,23 @@ export async function getCached(config: CloudflareBkndConfig, { env, ctx, ...arg
...makeCfConfig(config, { env, ctx, ...args }),
initialConfig,
onBuilt: async (app) => {
app.module.server.client.get("/__bknd/cache", async (c) => {
app.module.server.client.get(constants.cache_endpoint, async (c) => {
await kv.delete(key);
return c.json({ message: "Cache cleared" });
});
await config.onBuilt?.(app);
},
beforeBuild: async (app) => {
app.emgr.onEvent(
App.Events.AppBeforeResponse,
async (event) => {
ctx.waitUntil(event.params.app.emgr.executeAsyncs());
},
{
mode: "sync",
id: constants.exec_async_event_id,
},
);
app.emgr.onEvent(
App.Events.AppConfigUpdatedEvent,
async ({ params: { app } }) => {

View File

@@ -1,7 +1,7 @@
import { DurableObject } from "cloudflare:workers";
import type { App, CreateAppConfig } from "bknd";
import { App, type CreateAppConfig } from "bknd";
import { createRuntimeApp, makeConfig } from "bknd/adapter";
import type { CloudflareBkndConfig, Context } from "../index";
import { type CloudflareBkndConfig, type Context, constants } from "../index";
export async function getDurable(config: CloudflareBkndConfig, ctx: Context) {
const { dobj } = config.bindings?.(ctx.env)!;
@@ -67,7 +67,17 @@ export class DurableBkndApp extends DurableObject {
this.app = await createRuntimeApp({
...config,
onBuilt: async (app) => {
app.modules.server.get("/__do", async (c) => {
app.emgr.onEvent(
App.Events.AppBeforeResponse,
async (event) => {
this.ctx.waitUntil(event.params.app.emgr.executeAsyncs());
},
{
mode: "sync",
id: constants.exec_async_event_id,
},
);
app.modules.server.get(constants.do_endpoint, async (c) => {
// @ts-ignore
const context: any = c.req.raw.cf ? c.req.raw.cf : c.env.cf;
return c.json({
@@ -92,7 +102,6 @@ export class DurableBkndApp extends DurableObject {
this.keepAlive(options.keepAliveSeconds);
}
console.log("id", this.id);
const res = await this.app!.fetch(request);
const headers = new Headers(res.headers);
headers.set("X-BuildTime", buildtime.toString());
@@ -109,16 +118,13 @@ export class DurableBkndApp extends DurableObject {
async beforeBuild(app: App) {}
protected keepAlive(seconds: number) {
console.log("keep alive for", seconds);
if (this.interval) {
console.log("clearing, there is a new");
clearInterval(this.interval);
}
let i = 0;
this.interval = setInterval(() => {
i += 1;
//console.log("keep-alive", i);
if (i === seconds) {
console.log("cleared");
clearInterval(this.interval);

View File

@@ -1,12 +1,25 @@
import type { App } from "bknd";
import { App } from "bknd";
import { createRuntimeApp } from "bknd/adapter";
import { type CloudflareBkndConfig, type Context, makeCfConfig } from "../index";
import { type CloudflareBkndConfig, type Context, makeCfConfig, constants } from "../index";
export async function makeApp(config: CloudflareBkndConfig, ctx: Context) {
return await createRuntimeApp(
{
...makeCfConfig(config, ctx),
adminOptions: config.html ? { html: config.html } : undefined,
onBuilt: async (app) => {
app.emgr.onEvent(
App.Events.AppBeforeResponse,
async (event) => {
ctx.ctx.waitUntil(event.params.app.emgr.executeAsyncs());
},
{
mode: "sync",
id: constants.exec_async_event_id,
},
);
await config.onBuilt?.(app);
},
},
ctx,
);