Skip to content

fix(sync): let td-sync admin create-user run while the server writes - #215

Merged
marcus merged 1 commit into
marcus:mainfrom
jubishop:worktree-create-user-lock
Oct 15, 2026
Merged

marcus merged 1 commit into
marcus:mainfrom
jubishop:worktree-create-user-lock

Conversation

@jubishop

@jubishop jubishop commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #213. This branch includes #213's commit; only the last commit, 5a1fce0, is new. After #213 merges, this PR shows just that commit.

Summary

serverdb.CreateUser counted users and then inserted the new one in a deferred transaction. If another process wrote to server.db between those two steps, it failed immediately with database is locked, without waiting for the busy timeout. As a result, td-sync admin create-user failed against a running server, and #213 had to tell operators to stop the server first.

CreateUser now takes the write lock up front with BEGIN IMMEDIATE on a pinned connection, as ApproveDeviceChallengeAsOperator does in #213. The count and the insert remain atomic, so only the first user becomes admin, and the error strings are unchanged.

The HTTP sign-up and add-member paths share CreateUser. On the server they already ran one at a time on its single connection. The only change for them is that they now wait out another process's write instead of failing.

#213's "stop the server first" wording is removed from the admin usage line, the runAdminCreateUser comment, and the ops guide.

Testing

  • New TestAdminCreateUser_WhileServerWrites creates eight users as child processes while the test process keeps writing. It then reruns one to check that the command is still idempotent, and checks that only the first user is admin. It failed 19 of 20 runs on the old code and passed 30 of 30 after the change.
  • make test, go vet ./..., and gofmt pass, and golangci-lint v2.13.1 with GOOS=linux reports 0 issues. go test -race -count=1 passes for cmd/td-sync, internal/serverdb, and internal/api.

🤖 Generated with Claude Code

@jubishop
jubishop force-pushed the worktree-create-user-lock branch from f68f5ca to 5a1fce0 Compare October 15, 2026 21:14
CreateUser counted users and then inserted in one deferred transaction,
so a write from a running server in between made it fail at once with
"database is locked". It now takes the write lock up front with BEGIN
IMMEDIATE, as ApproveDeviceChallengeAsOperator does, and the docs no
longer say to stop the server first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@marcus
marcus force-pushed the worktree-create-user-lock branch from 5a1fce0 to 21a5a66 Compare October 15, 2026 22:26
@marcus
marcus merged commit 154862a into marcus:main Oct 15, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants