openConcurrentDB opens flow.db with a generous busy_timeout so that two concurrent `flow do` processes (or two goroutines in the tests) will serialize at the SQLite file level rather than failing fast with SQLITE_BUSY. The pragma is applied at connection-open time via the DSN so every conn in the po
(path string)
| 64 | // so every conn in the pool inherits it. Schema creation still runs via |
| 65 | // OpenDB to keep DDL in one place. |
| 66 | func openConcurrentDB(path string) (*sql.DB, error) { |
| 67 | // Ensure schema exists via the shared OpenDB path. |
| 68 | pre, err := flowdb.OpenDB(path) |
| 69 | if err != nil { |
| 70 | return nil, err |
| 71 | } |
| 72 | pre.Close() |
| 73 | |
| 74 | q := url.Values{} |
| 75 | // 30s is enough to cover realistic bootstraps; tests finish in ms. |
| 76 | q.Set("_pragma", "busy_timeout(30000)") |
| 77 | // BEGIN IMMEDIATE acquires a RESERVED lock up-front, so two concurrent |
| 78 | // `flow do` transactions serialize at tx.Begin() (waiting on the busy |
| 79 | // timeout) instead of racing to the first write and failing. |
| 80 | q.Set("_txlock", "immediate") |
| 81 | dsn := "file:" + path + "?" + q.Encode() |
| 82 | db, err := sql.Open("sqlite", dsn) |
| 83 | if err != nil { |
| 84 | return nil, fmt.Errorf("open sqlite %s: %w", path, err) |
| 85 | } |
| 86 | if _, err := db.Exec("PRAGMA foreign_keys = ON"); err != nil { |
| 87 | db.Close() |
| 88 | return nil, fmt.Errorf("enable foreign_keys: %w", err) |
| 89 | } |
| 90 | return db, nil |
| 91 | } |
| 92 | |
| 93 | // cmdDo flips a task to in-progress, bootstraps a Claude session if |
| 94 | // needed (race-free via atomic UPDATE ... WHERE session_id IS ?), and |
no test coverage detected