Skip to content

[17.0-rc][疑似平台] os migrate apply 对运行中服务正在使用的 SQLite 库缺少占用检测 #526

Description

@yinlianghui

现象

dev server 正在使用某个 SQLite 库时,对同一库执行 os migrate apply(含 replace_unique_index 等重建型变更)没有任何占用告警或拒绝。

CLI 与运行中服务并发改库存在文件被替换/状态分叉的风险(本次测试未实际复现数据损坏,属预防性反馈)。建议 CLI 检测库被占用时给出警告或要求 --force。

详见分支 upgrade/objectstack-17 的 docs/upgrade-17/test-report.md §3 P7。

Activity

  1. yinlianghui commented on Jul 29, 2026

    @yinlianghui
    CollaboratorAuthor

    源码核实修正:migrate apply 确认全路径无占用检测,且 runtime.start() 在确认提示前就执行 schema-sync DDL;但原 issue 中「文件 inode 被替换」的猜测不成立——replace_unique_index 是纯索引 DDL,SQLite 列级重建也只在库内换表不换文件(sql-driver.ts:2816-2877),实际风险是 stale prepared statements / SQLITE_BUSY。已按修正后的事实上报平台:objectstack-ai/objectstack#3917

  2. yinlianghui commented on Jul 29, 2026

    @yinlianghui
    CollaboratorAuthor

    📎 分支 upgrade/objectstack-17 已推送至上游(仅分支,无 PR,勿合并——阻塞于 17.0 正式版与 objectstack#3912/#3913/#3914)。正文引用的文档现在可直接访问:测试报告 | 测试计划

  3. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    CollaboratorAuthor

    rc.2 retest: 已解除(occupancy detection + confirmation gate are both in place)

    Retested on @objectstack/* 17.0.0-rc.2 (current main, commit 5a78f88), on an isolated dev server (port 4009, own DB file) so nothing shared was at risk. Full chain, each step observed:

    1. migrate plan against the live DB now warns up front:

    ⚠ …/data.db is in use — it is open in pid 4468 (node) (data.db-wal, data.db-shm present).
      The plan below is still accurate — nothing is written — but "os migrate apply"
      will refuse until it is free (or you pass --force).
    

    2. migrate apply --allow-destructive against the live DB refuses before any DDL:

    → Checking whether the database is in use…
    ✗ …/data.db is in use — it is open in pid 4468 (node) (data.db-wal, data.db-shm present).
    ⚠ Stop the process using it (a running "os dev"/"os serve" is the usual one) and re-run,
      or pass --force to migrate anyway.
    

    Verified nothing was written: the drift column I had planted (crm_task.zz_orphan_probe, created directly in the disposable DB to have something to drop) was still present afterwards.

    3. Even with the server stopped, apply now demands explicit confirmation — rc.0's "DDL before confirmation" behaviour is gone:

    ⚠ Destructive changes assume your full app/plugin set is loaded. A column that looks
      "orphaned" here may belong to a plugin that is not part of this build.
    ⚠ Confirmation required. Re-run with --yes to apply, or use "os migrate plan" to preview.
    

    4. With the server stopped and --yes: ✓ Applied 1 change(s). and the probe column is gone.

    So both halves of this issue — no occupancy detection, and DDL issued before confirmation — are fixed, with an explicit --force escape hatch for the intentional case. Upstream objectstack#3917's remedy is present in the rc.2 CLI.

    One residual nit, recorded here rather than filed: the occupied-DB refusal exits with code 0. A CI script doing os migrate apply && deploy would treat the refusal as success and deploy against an unmigrated schema. Worth a follow-up if the owner agrees; it is a much smaller defect than the one this issue tracked.

    Recommend closing after owner confirmation (this run's mandate is test-don't-fix, so I'm reporting rather than closing).


    Generated by Claude Code

  4. yinlianghui commented on Aug 5, 2026

    @yinlianghui
    CollaboratorAuthor

    [17.0-rc2验收复核] 结论:已不复现(占用检测 + 拒绝执行均在;且拒绝以非零码退出)

    证据:对本组自己的 scratch 库(dev server 运行中,WAL/SHM 在盘)实测:

    # plan:预警但照常出计划(只读)
    pnpm exec objectstack migrate plan --database-url file:…/a1/data.db
    → ⚠ …/a1/data.db is in use — it is open in pid 9372 (node) (data.db-wal, data.db-shm present).
      The plan below is still accurate — nothing is written — but "os migrate apply" will refuse until it is free (or you pass --force).
    
    # apply:执行前拒绝
    pnpm exec objectstack migrate apply --database-url file:…/a1/data.db
    → → Checking whether the database is in use…
      ✗ …/a1/data.db is in use — it is open in pid 9372 (node) …
      ⚠ Stop the process using it … or pass --force to migrate anyway.
      退出码 = 1
    

    控制组:向该库故意 ALTER TABLE crm_task ADD COLUMN zz_a1_probe 后,plan 正确判 ✗ crm_task.zz_a1_probe [drop_column](destructive)——即上面的干净结论出自活着的检测器;拒绝路径确认未写任何 DDL(探针列复查仍在,测毕已删)。

    一处与今晨复测(5a78f88)的差异,记录以免误传:该次记录「occupied-DB 拒绝 exit code 0」;本组在 0899b4f 上经 pnpm exec 实测退出码为 1(echo $? 直接取得)。CI 场景 apply && deploy 不会误判成功。停服 + --yes 的确认门本组未复测(服务器需继续供其余项使用),今晨复测已单独验证过该半。

    环境:hotcrm@0899b4f + @objectstack 17.0.0-rc.2

    建议:前提已过时建议关闭(objectstack#3917 的补救在 rc.2 CLI 确认存在)。


    Generated by Claude Code

  5. hotlong commented on Aug 14, 2026

    @hotlong
    Contributor

    Closing — provenance

    Closed as part of the GA close-out bookkeeping sweep (#1151, group 3), on the recorded on-card evidence below. No new probe was run; this is a bookkeeping close of a reading already taken.

    (a) Version. @objectstack/* 17.0.0-rc.2 — read twice: once at repo commit 5a78f88 on an isolated dev server (port 4009, own DB file), once independently at hotcrm@0899b4f against a scratch DB.

    (b) Probe. os migrate plan and os migrate apply run against a SQLite database held open by a live dev server (WAL/SHM present on disk), with a deliberately planted drift column as the control:

    pnpm exec objectstack migrate plan  --database-url file:…/data.db
    pnpm exec objectstack migrate apply --database-url file:…/data.db
    ALTER TABLE crm_task ADD COLUMN zz_a1_probe      (control: gives the planner something real to find)
    

    (c) Result. Both halves of this card are fixed, and the --force escape hatch exists for the intentional case:

    • Occupancy detection exists. plan warns up front — "…data.db is in use — it is open in pid 4468 (node) (data.db-wal, data.db-shm present)" — while still producing an accurate read-only plan.
    • apply refuses before any DDL, with "→ Checking whether the database is in use…" then "✗ …is in use… Stop the process using it… or pass --force to migrate anyway." Verified nothing was written: the planted probe column was still present afterwards.
    • The rc.0 "DDL before confirmation" behaviour is also gone — even with the server stopped, apply demands --yes before applying; with --yes it reports ✓ Applied 1 change(s). and the probe column is dropped.
    • The control group confirms the detector is alive rather than vacuous: with the probe column planted, plan correctly classifies ✗ crm_task.zz_a1_probe [drop_column] as destructive.

    Upstream objectstack#3917's remedy is present in the rc.2 CLI.

    (d) Source comments.

    Both readings recommend closing.

    (e) Authority. #1150, on maintainer ruling 2026-08-14 (verbatim 「同意」); dispatched as #1151 group 3.

    One recorded disagreement between the two readings, resolved

    The first reading flagged a residual: "the occupied-DB refusal exits with code 0", which would let a CI apply && deploy treat a refusal as success. The second reading measured the exit code directly (echo $? after pnpm exec) and got 1. The later, more direct measurement stands — the CI hazard does not exist. Recording it here so the first comment's nit is not carried forward as an open item.

    The confirmation gate with the server stopped (--yes) was verified by the first reading only; the second did not re-run it because its server had to stay up for other work. That half is single-sourced but unambiguous.


    Generated by Claude Code


    Generated by Claude Code

  6. added and removed on Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority:p2Medium: important, M3upstream:objectstackBlocked on / caused by the ObjectStack platform — tracked upstream

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions