push-day --tomorrow runs headless in the image (token from the environment); the app's on-box prepare is off (MOSAIC_DAILY_PREPARE=0) so it never contends with play; rollover prefers the pushed field, then a prepared one, then the emergency field; /status reports whether tomorrow's field is pushed.
- commit
- 0cff06655bcb6c24a236b4c39bd439a521e9d120
- parent
- 0ed7d0da406769e3683638cb4b0b0534fa817893
- author
- dami <gazey55@gmail.com>
| M | fly.toml | 3 | +++ |
| M | site/ | 34 | +++++++++++++++++++++++++++--- |
| M | site/ | 1 | + |
| M | site/ | 12 | ++++++++++- |
| M | site/ | 1 | + |
@@ -12,7 +12,10 @@ primary_region = "dfw"
1212 [env]1313 # the nightly prepare runs here: tomorrow's field from 20:00 UTC,1414 # killed at rollover if it overruns; a pushed field is the fallback15+ # generation here is the emergency fallback only; the nightly runs on16+ # the scheduled machine mosaic-nightly (performance-4x) and pushes1517 MOSAIC_GENERATE = '1'18+ MOSAIC_DAILY_PREPARE = '0'1619 MOSAIC_DAILY_PREPARE_UTC = '20'1720 MOSAIC_DAILY_JOBS = '2'1821 MOSAIC_DAILY_BAND = '24'@@ -45,6 +45,10 @@ export type DailyConfig = {
4545 fog: boolean;4646 /** run the engine on this box (fields can also be pushed) */4747 generate: boolean;48+ /** run the nightly prepare on this box; off when a scheduled machine49+ * pushes tomorrow's field (the app machine then only serves, and50+ * generates nothing but an emergency field) */51+ prepare: boolean;4852 /** the nightly prepare of tomorrow's field starts at this UTC hour and4953 * must finish by rollover (its deadline); jobs = chunk processes at once */5054 prepare_hour_utc: number;@@ -72,6 +76,7 @@ export function configFromEnv(): DailyConfig {
7276 rollover_hour_utc: Number(Deno.env.get("MOSAIC_DAILY_ROLLOVER_UTC") ?? 0),7377 fog: (Deno.env.get("MOSAIC_DAILY_FOG") ?? "1") !== "0",7478 generate: Deno.env.get("MOSAIC_GENERATE") === "1",79+ prepare: (Deno.env.get("MOSAIC_DAILY_PREPARE") ?? "1") !== "0",7580 prepare_hour_utc: Number(Deno.env.get("MOSAIC_DAILY_PREPARE_UTC") ?? 20),7681 jobs: num("MOSAIC_DAILY_JOBS", 2),7782 band: num("MOSAIC_DAILY_BAND", 24),@@ -289,6 +294,8 @@ export type DailyStatus = {
289294 since_s: number | null; // seconds spent generating so far290295 emergency: boolean;291296 latest_archived: { date: string; game_id: string } | null;297+ /** tomorrow's field: pushed to this box, or prepared in its cache */298+ tomorrow: { date: string; pushed: boolean; prepared: boolean };292299 };293300 294301 export type DailyState = {@@ -386,6 +393,10 @@ export class Daily {
386393 date: string,387394 seed: string,388395 ): Promise<{ out: FieldOutput; source: DailyState["source"] } | null> {396+ // a pushed field wins: it was made by a machine that could afford397+ // the whole thing; the on-box prepare is the fallback for it398+ const pushed = await loadPushed(this.dir, date);399+ if (pushed) return { out: pushed, source: "pushed" };389400 const full = this.genParams(390401 date,391402 seed,@@ -396,8 +407,6 @@ export class Daily {
396407 if (this.canGenerate && await this.isPrepared(full)) {397408 return { out: await this.generate(full), source: "prepared" };398409 }399- const pushed = await loadPushed(this.dir, date);400- if (pushed) return { out: pushed, source: "pushed" };401410 if (!this.canGenerate) return null;402411 const e = this.cfg.emergency;403412 this.log(@@ -537,7 +546,13 @@ export class Daily {
537546 if (!this.current || !getGame(this.current.game_id)) {538547 await this.startDay(today);539548 }540- if (this.canGenerate) this.maybePrepare(today);549+ if (this.canGenerate && this.cfg.prepare) this.maybePrepare(today);550+ else if (this.lastPrepareLog !== "external") {551+ this.lastPrepareLog = "external";552+ this.log(553+ "nightly prepare is external: tomorrow's field is pushed by the nightly machine; this box generates only an emergency field",554+ );555+ }541556 }542557 543558 /** The nightly job: from the prepare hour, generate tomorrow's field@@ -740,6 +755,14 @@ export class Daily {
740755 /** What `/` should show right now. */741756 status(): DailyStatus {742757 const cur = this.current;758+ const tomorrow = nextDate(this.today());759+ let pushed = false;760+ try {761+ Deno.statSync(pushedPath(this.dir, tomorrow));762+ pushed = true;763+ } catch {764+ // not yet765+ }743766 const live = cur && getGame(cur.game_id) ? cur.game_id : null;744767 const latest = this.index.list().at(-1) ?? null;745768 const today = this.today();@@ -756,6 +779,11 @@ export class Daily {
756779 latest_archived: latest757780 ? { date: latest.date, game_id: latest.game_id }758781 : null,782+ tomorrow: {783+ date: tomorrow,784+ pushed,785+ prepared: this.prepared.has(tomorrow),786+ },759787 };760788 }761789 @@ -15,6 +15,7 @@ export const handler = define.handlers({
1515 since_s: null,1616 emergency: false,1717 latest_archived: null,18+ tomorrow: { date: "", pushed: false, prepared: false },1819 }, { headers: { "Cache-Control": "no-store" } });1920 }2021 return Response.json(d.status(), {@@ -2,6 +2,7 @@
22 //33 // deno task push-day 2026-08-28 [--host https://mosaic-daily.fly.dev]44 // [--chunks 3] [--chunk-g 60] [--G 1000] [--rings 2] [--namespace mosaic-daily]5+// deno task push-day --tomorrow ... (the nightly machine: tomorrow, UTC)56 //67 // The token comes from MOSAIC_PUSH_TOKEN or ~/.config/mosaic/push-token.78 // The field parameters must match the hosted daily's configuration (its@@ -33,6 +34,7 @@ const cfg = {
3334 rollover_hour_utc: 0,3435 fog: true,3536 generate: true,37+ prepare: true,3638 prepare_hour_utc: 20,3739 jobs: Number(args.jobs ?? 2),3840 band: Number(args.band ?? 24),@@ -42,7 +44,15 @@ async function token(): Promise<string> {
4244 const env = Deno.env.get("MOSAIC_PUSH_TOKEN");4345 if (env) return env;4446 const home = Deno.env.get("HOME") ?? "";45- return (await Deno.readTextFile(`${home}/.config/mosaic/push-token`)).trim();47+ try {48+ return (await Deno.readTextFile(`${home}/.config/mosaic/push-token`))49+ .trim();50+ } catch {51+ console.error(52+ "no MOSAIC_PUSH_TOKEN in the environment and no ~/.config/mosaic/push-token",53+ );54+ Deno.exit(2);55+ }4656 }4757 const seed = await seedFor(date, cfg);4858 console.log(