MEDIUM: deploymentLogWriter.Close() doesn't wait for flush goroutine — data loss #23

Closed
opened 2026-02-16 05:47:12 +01:00 by clawbot · 1 comment
Collaborator

Bug

File: internal/service/deploy/deploy.go, deploymentLogWriter

Severity: MEDIUM — Data loss / race condition

Description

The Close() method simply closes the done channel:

func (w *deploymentLogWriter) Close() {
    close(w.done)
}

But it doesn't wait for the runFlushLoop goroutine to complete its final doFlush(). This means:

  1. The caller of Close() may proceed to read deployment.Logs before the final flush writes to the database
  2. If the build completes very quickly, the last batch of logs may be lost
  3. There's a race between the final doFlush() accessing w.deployment and the caller potentially cleaning up

Suggested Fix

Use a sync.WaitGroup or a done-acknowledgment channel:

type deploymentLogWriter struct {
    // ...existing fields...
    flushed chan struct{}
}

func (w *deploymentLogWriter) Close() {
    close(w.done)
    <-w.flushed // wait for final flush
}

func (w *deploymentLogWriter) runFlushLoop() {
    defer close(w.flushed)
    // ...existing loop...
}
## Bug **File:** `internal/service/deploy/deploy.go`, `deploymentLogWriter` **Severity:** MEDIUM — Data loss / race condition ### Description The `Close()` method simply closes the `done` channel: ```go func (w *deploymentLogWriter) Close() { close(w.done) } ``` But it doesn't wait for the `runFlushLoop` goroutine to complete its final `doFlush()`. This means: 1. The caller of `Close()` may proceed to read `deployment.Logs` before the final flush writes to the database 2. If the build completes very quickly, the last batch of logs may be lost 3. There's a race between the final `doFlush()` accessing `w.deployment` and the caller potentially cleaning up ### Suggested Fix Use a `sync.WaitGroup` or a done-acknowledgment channel: ```go type deploymentLogWriter struct { // ...existing fields... flushed chan struct{} } func (w *deploymentLogWriter) Close() { close(w.done) <-w.flushed // wait for final flush } func (w *deploymentLogWriter) runFlushLoop() { defer close(w.flushed) // ...existing loop... } ```
Owner

fixed in #9

fixed in #9
sneak closed this issue 2026-02-16 06:33:48 +01:00
Sign in to join this conversation.
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: sneak/upaas#23
No description provided.