fix(core): Add structured error handling and responsive lock release
Improves core infrastructure with robot-friendly error output and faster lock release for better sync behavior. Error handling improvements (error.rs): - ErrorCode::exit_code(): Unique exit codes per error type (1-13) for programmatic error handling in scripts/agents - GiError::suggestion(): Helpful hints for common error recovery - GiError::to_robot_error(): Structured JSON error conversion - RobotError/RobotErrorOutput: Serializable error types with code, message, and optional suggestion fields Lock improvements (lock.rs): - Heartbeat thread now polls every 100ms for release flag, only updating database heartbeat at full interval (5s default) - Eliminates 5-10s delay after sync completion when waiting for heartbeat thread to notice release - Reduces lock hold time after operation completes Database (db.rs): - Bump expected schema version to 6 for MR migration The exit code mapping enables shell scripts and CI/CD pipelines to distinguish between configuration errors (2-4), GitLab API errors (5-8), and database errors (9-11) for appropriate retry/alert logic. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -42,10 +42,7 @@ pub struct AppLock {
|
||||
impl AppLock {
|
||||
/// Create a new app lock instance.
|
||||
pub fn new(conn: Connection, options: LockOptions) -> Self {
|
||||
let db_path = conn
|
||||
.path()
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_default();
|
||||
let db_path = conn.path().map(PathBuf::from).unwrap_or_default();
|
||||
|
||||
Self {
|
||||
conn,
|
||||
@@ -73,7 +70,9 @@ impl AppLock {
|
||||
let now = now_ms();
|
||||
|
||||
// Use IMMEDIATE transaction to prevent race conditions
|
||||
let tx = self.conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
|
||||
let tx = self
|
||||
.conn
|
||||
.transaction_with_behavior(TransactionBehavior::Immediate)?;
|
||||
|
||||
// Check for existing lock within the transaction
|
||||
let existing: Option<(String, i64, i64)> = tx
|
||||
@@ -176,9 +175,21 @@ impl AppLock {
|
||||
}
|
||||
};
|
||||
|
||||
loop {
|
||||
thread::sleep(interval);
|
||||
// Poll frequently for early exit, but only update heartbeat at full interval
|
||||
const POLL_INTERVAL: Duration = Duration::from_millis(100);
|
||||
|
||||
loop {
|
||||
// Sleep in small increments, checking released flag frequently
|
||||
let mut elapsed = Duration::ZERO;
|
||||
while elapsed < interval {
|
||||
thread::sleep(POLL_INTERVAL);
|
||||
elapsed += POLL_INTERVAL;
|
||||
if released.load(Ordering::SeqCst) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check once more after full interval elapsed
|
||||
if released.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user