Repository navigation
feat(sync): stop stages 3 and 4 at the runner's time budget #1167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| 'use strict'; | ||
|
|
||
| /** | ||
| * Per-run time budget and metrics (own-episode-IDs P3b, hourly runs). | ||
| * | ||
| * The VPS runner (netcup-panel `boxlore-sync/run-sync.sh`) gives each run a time budget once it | ||
| * holds the shared job lock: 30 minutes for hourly runs, 45 for the nightly chart and cleanup | ||
| * runs. It passes two deadlines as epoch seconds: | ||
| * SYNC_STAGE3_DEADLINE_AT — stage 3 stops checking shows (half the budget); | ||
| * SYNC_DEADLINE_AT — stage 4 stops embedding. | ||
| * Work left over (shows still due, backlog) waits for the next run, so runs stay even instead of | ||
| * one long run after a quiet one. Unset deadlines mean no limit (manual runs, CI). | ||
| * | ||
| * Stages append one JSON line of counts to SYNC_METRICS_FILE for the runner's usage log. | ||
| */ | ||
|
|
||
| const fs = require('fs'); | ||
|
|
||
| const STAGE3_DEADLINE = 'SYNC_STAGE3_DEADLINE_AT'; | ||
| const RUN_DEADLINE = 'SYNC_DEADLINE_AT'; | ||
|
|
||
| /** Deadline in epoch ms from an env var holding epoch seconds; Infinity when unset or invalid. */ | ||
| function deadlineFrom(name, env = process.env) { | ||
| const raw = String(env[name] ?? '').trim(); | ||
| const s = /^[0-9]+$/.test(raw) ? Number(raw) : 0; | ||
| return s > 0 ? s * 1000 : Infinity; | ||
| } | ||
|
|
||
| /** The earlier of the stage's own deadline and the run's. */ | ||
| function stageDeadline(stageVar, env = process.env) { | ||
| return Math.min(deadlineFrom(stageVar, env), deadlineFrom(RUN_DEADLINE, env)); | ||
| } | ||
|
|
||
| function timeUp(deadlineMs, now = Date.now()) { | ||
| return now >= deadlineMs; | ||
| } | ||
|
|
||
| /** Appends one metrics line for the runner's usage log. Never throws. */ | ||
| function recordMetrics(stage, data, env = process.env) { | ||
| const file = env.SYNC_METRICS_FILE; | ||
| if (!file) return false; | ||
| try { | ||
| fs.appendFileSync(file, `${JSON.stringify({ stage, t: Math.floor(Date.now() / 1000), ...data })}\n`); | ||
| return true; | ||
| } catch { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| module.exports = { STAGE3_DEADLINE, RUN_DEADLINE, deadlineFrom, stageDeadline, timeUp, recordMetrics }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| 'use strict'; | ||
|
|
||
| const test = require('node:test'); | ||
| const assert = require('node:assert/strict'); | ||
| const fs = require('node:fs'); | ||
| const os = require('node:os'); | ||
| const path = require('node:path'); | ||
| const { STAGE3_DEADLINE, RUN_DEADLINE, deadlineFrom, stageDeadline, timeUp, recordMetrics } = require('./run-budget'); | ||
|
|
||
| test('deadlines come from epoch seconds; unset or malformed means no limit', () => { | ||
| assert.equal(deadlineFrom(RUN_DEADLINE, { [RUN_DEADLINE]: '1792800000' }), 1_792_800_000_000); | ||
| assert.equal(deadlineFrom(RUN_DEADLINE, { [RUN_DEADLINE]: ' 1792800000 ' }), 1_792_800_000_000); | ||
| for (const bad of [undefined, '', '0', '1.5e9', 'soon', '-5']) { | ||
| assert.equal(deadlineFrom(RUN_DEADLINE, { [RUN_DEADLINE]: bad }), Infinity, String(bad)); | ||
| } | ||
| }); | ||
|
|
||
| test('a stage stops at the earlier of its own deadline and the run\'s', () => { | ||
| assert.equal(stageDeadline(STAGE3_DEADLINE, { [STAGE3_DEADLINE]: '100', [RUN_DEADLINE]: '200' }), 100_000); | ||
| assert.equal(stageDeadline(STAGE3_DEADLINE, { [STAGE3_DEADLINE]: '300', [RUN_DEADLINE]: '200' }), 200_000); | ||
| assert.equal(stageDeadline(STAGE3_DEADLINE, { [RUN_DEADLINE]: '200' }), 200_000); | ||
| assert.equal(stageDeadline(STAGE3_DEADLINE, {}), Infinity); | ||
| }); | ||
|
|
||
| test('timeUp at and after the deadline only', () => { | ||
| assert.equal(timeUp(1000, 999), false); | ||
| assert.equal(timeUp(1000, 1000), true); | ||
| assert.equal(timeUp(Infinity), false); | ||
| }); | ||
|
|
||
| test('metrics: one JSON line per call; no file configured means nothing written', () => { | ||
| const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'run-metrics-')); | ||
| const file = path.join(dir, 'm.jsonl'); | ||
| try { | ||
| assert.equal(recordMetrics('03-sync-episodes', { checked: 5, timeUp: true }, { SYNC_METRICS_FILE: file }), true); | ||
| assert.equal(recordMetrics('04-vectorize-episodes', { embedded: 2 }, { SYNC_METRICS_FILE: file }), true); | ||
| const lines = fs.readFileSync(file, 'utf8').trim().split('\n').map((l) => JSON.parse(l)); | ||
| assert.deepEqual(lines.map((l) => [l.stage, l.checked ?? l.embedded]), [['03-sync-episodes', 5], ['04-vectorize-episodes', 2]]); | ||
| assert.equal(typeof lines[0].t, 'number'); | ||
| assert.equal(recordMetrics('x', {}, {}), false); | ||
| assert.equal(recordMetrics('x', {}, { SYNC_METRICS_FILE: path.join(dir, 'missing', 'm.jsonl') }), false, 'never throws'); | ||
| } finally { | ||
| fs.rmSync(dir, { recursive: true, force: true }); | ||
| } | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.