跳到正文
DEV Community· Morgan Xu·· 3 小時前AI 評分53

如何輪班管理共享免費額度,避免交接時工作停滯

Rotate a Shared Free Allowance Without Losing Work

AI 導讀

文章提出共享免費額度的輪班管理方案,透過三個角色分工、SQLite 用量記錄及作業前檢查,減少交接時工作停滯。範例將 10,000,000 tokens 設為記帳上限,但這不會限制供應商用量,並行檢查亦可能同時放行多項工作;文章提出單一寫入者、加鎖或預先記錄預留額度作為緩解方式。

正文

A shared free allowance rarely fails from capacity. It fails at handoff. Two people draw from one pool. Neither owns the last hour of it. Work stalls at the shift change, not at the hard limit.

That pattern repeats on every team that treats a free tier as infrastructure. The allowance is real. The coordination around it is missing. A one-page rotation card removes most of the friction.

The last hour carries the risk

Free tiers attract small, bursty jobs. A migration dry run. A batch of test generations. A refactor across four files. Each job is cheap in isolation. Together they drain the pool before the next person looks.

The usual fix is a shared spreadsheet. The spreadsheet is stale by noon. Nobody edits a row while a build is failing.

A ledger beats a spreadsheet because the gate runs in the same shell as the job. The check happens at claim time. The record is a side effect, not a chore.

Three roles on a four-hour rotation

The Budget Keeper owns the cap. Only the Keeper approves a job above the per-job ceiling. That authority travels with the shift, not with seniority.

The Bench Runner owns the queue. The Runner starts jobs, watches them, and cancels early when output quality drops. Early cancellation is the cheapest saving available.

The Handoff Clerk writes the card at shift end. The card is ten lines, not a report. It names what finished, what is running, and what remains.

One person may hold two roles on a small team. Nobody holds all three for more than one shift. The separation exists to make the transfer visible.

A ledger that runs locally

The script below stores spend in SQLite. It makes no network calls. Any team can rehearse it against a free tier without touching product APIs.

#!/usr/bin/env python3
"""ledger.py - local token bookkeeping. No network calls."""
import argparse, sqlite3, sys, time

DB = "allowance.db"
CAP = 10_000_000  # stated free allowance; confirm on the project site

def con():
    c = sqlite3.connect(DB)
    c.execute("""CREATE TABLE IF NOT EXISTS spend(
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        shift TEXT NOT NULL,
        job TEXT NOT NULL,
        tokens INTEGER NOT NULL,
        ts INTEGER NOT NULL)""")
    return c

def total(c):
    return c.execute("SELECT COALESCE(SUM(tokens),0) FROM spend").fetchone()[0]

def check(cost):
    with con() as c:
        used = total(c)
        return used + cost <= CAP, used

def record(shift, job, tokens):
    with con() as c:
        c.execute(
            "INSERT INTO spend(shift,job,tokens,ts) VALUES(?,?,?,?)",
            (shift, job, tokens, int(time.time())),
        )

def report():
    with con() as c:
        return c.execute(
            "SELECT shift, SUM(tokens) FROM spend GROUP BY shift"
        ).fetchall()

if __name__ == "__main__":
    p = argparse.ArgumentParser()
    sub = p.add_subparsers(dest="cmd", required=True)

    chk = sub.add_parser("check")
    chk.add_argument("--cost", type=int, required=True)

    rec = sub.add_parser("record")
    rec.add_argument("--shift", required=True)
    rec.add_argument("--job", required=True)
    rec.add_argument("--tokens", type=int, required=True)

    sub.add_parser("report")
    a = p.parse_args()

    if a.cmd == "check":
        ok, used = check(a.cost)
        print(f"used={used} cap={CAP} cost={a.cost} ok={ok}")
        sys.exit(0 if ok else 1)
    if a.cmd == "record":
        record(a.shift, a.job, a.tokens)
    if a.cmd == "report":
        for shift, tokens in report():
            print(f"{shift}\t{tokens}")

The constant CAP is bookkeeping, not enforcement. A team that edits the file can lie to itself. That is acceptable when the same team owns the pool.

Wire the gate into the job script first. Order matters more than elegance.

python3 ledger.py check --cost 4200 && ./run_job.sh

A failed check returns exit code 1. The shell stops. Nothing is spent.

python3 ledger.py check --cost 900000 || echo "escalate to keeper"
python3 ledger.py record --shift 06-10 --job job-42 --tokens 4180

Close the loop after each job. The record step is manual in this version. Automation can read usage from the job logs instead.

A nightly rollup keeps the wiki honest.

sqlite3 allowance.db \
  "SELECT shift, SUM(tokens) FROM spend GROUP BY shift ORDER BY 2 DESC;"

The decision table

The table below is the whole policy. Post it next to the rotation schedule.

Remaining allowance Action Owner
More than 3x job cost Run immediately Bench Runner
Between 1x and 3x job cost Split in half, re-check after part one Bench Runner
Less than job cost Park the job, notify next shift Budget Keeper
Less than job cost and urgent Move to a paid path or reschedule Budget Keeper

The split rule matters most. Halving a job usually reveals a cheaper prompt or a smaller batch. The information arrives before the allowance is gone.

The handoff card

Ten lines. Paste them into whatever wiki the team already reads.

SHIFT:      2026-10-17 06:00-10:00 UTC
KEEPER:     <name>
RUNNER:     <name>
SPENT:      <n> tokens this shift
REMAINING:  <n> tokens (source: ledger.py report)
RUNNING:    <job id, started, owner>
FINISHED:   <job id, quality note>
PARKED:     <job id, reason, next check>
RISK:       <one known unknown>
NEXT:       <one sentence, imperative>

The RISK line is not optional. It carries the thing the next shift would otherwise learn the hard way. A half-finished refactor. A test suite that only passes once. A queue that quietly grew.

Test the rotation before trusting it

Three checks take ten minutes. All of them run locally.

Simulate exhaustion by inserting a fake row, then confirm the gate closes.

sqlite3 allowance.db \
  "INSERT INTO spend(shift,job,tokens,ts) VALUES('test','burn',9999999,0);"
python3 ledger.py check --cost 4200; echo "exit=$?"
sqlite3 allowance.db "DELETE FROM spend WHERE job='burn';"

Expect exit=1. If the gate stays open, the cap or the SQL is wrong.

Kill a job mid-flight and confirm the ledger survives.

timeout 2 ./run_job.sh; python3 ledger.py report

Each row commits on its own. The report never shows a torn write.

Run two claims in the same second from two shells.

for i in 1 2; do python3 ledger.py check --cost 5000000 & done; wait

Both calls may pass. This version has no lock and no reservation. Two keepers writing at once will overrun the cap. Mitigate with a single writer, a flock wrapper, or by recording reservations before jobs instead of after.

That gap is the honest boundary of the artifact. Bookkeeping after the fact cannot throttle a provider.

Where MonkeyCode fits

The operator states two facts that matter here: free model access and a free server option. The same operator states a free allowance of roughly ten million tokens at the time of writing. Quotas, model lists, and server limits should be confirmed on the project site before planning around them. Assume nothing about permanence.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

The rotation card is provider-agnostic. It matters more when the pool is finite and shared. A free tier is a reasonable place to rehearse the roles before a team commits budget to anything.

If the card fits a team's habits, the free tier is a low-cost place to try it once.

Limitations and who should skip this

Teams with committed paid spend do not need a rotation. Their provider meters usage for them. The card adds ceremony without savings.

Latency-sensitive work should skip free pools entirely. A queue that waits on a shared allowance is not a queue anyone can promise against.

Regulated data should not land on a free server without a reviewed retention policy. Nobody in this workflow can answer that question. The security owner must.

Single developers can replace the whole structure with one shell alias and a number in a notes file. Three roles for one person is theatre.

A free pool is a shared resource. The handoff, not the limit, is the design problem.

來源:DEV Community · dev.to