Skip to content

fix(rust): log datastore write errors instead of discarding them - #366

Merged
ErikBjare merged 2 commits into
ActivityWatch:masterfrom
ThisIsLeoS:fix/rust-log-write-errors
Oct 14, 2026
Merged

ErikBjare merged 2 commits into
ActivityWatch:masterfrom
ThisIsLeoS:fix/rust-log-write-errors

Conversation

@ThisIsLeoS

Copy link
Copy Markdown
Contributor

Problem

heartbeat() reports a failed write by returning an {"error": …} object; it never throws. RustInterface.heartbeatHelper() discarded that response (its Log.w was commented out), and insertEvent() logged it only at debug level, mixed in with every successful response. A watcher whose writes fail therefore loses every event with nothing in logcat to show it.

One way to get there: deleting the media or web bucket from the web UI while the app runs. Those watchers create their bucket only when their service starts, so every later heartbeat fails with NoSuchBucket until the service is recreated. A datastore worker that has died fails all writes the same way.

Change

  • A new WriteFailureLog logs a warning for the first failed write of a run and, once a write to the same bucket succeeds again, how many failed in between. A line per failure would flood logcat, since watchers write every few seconds.
  • Runs are counted per bucket, in one log for the whole process: the batch watchers build a new RustInterface on every read, and a run of failures has to outlive them.
  • heartbeatHelper() and insertEvent() pass every response to it. insertEvent() no longer logs each response at debug level.
  • heartbeat() is declared String?: the native side returns null when it cannot build even its error object, and that counts as a failed write.
  • Corrects the comment in MediaWatcher.onCreate: its init calls never go through the HTTP server, so whether the server has started doesn't matter.

#359 reads the same {"error": …} object in getBucketsJSON(). Once one of the two PRs is merged, the other can reuse its check instead of adding a second copy.

Testing

  • New WriteFailureLogTest: no log on success, one line per run of failures, the recovery count, buckets counted separately, a missing response, and parsing of the error object.
  • ./gradlew :mobile:testStandardDebugUnitTest passes.

heartbeat() reports a failed write by returning an {"error": ...} object
rather than throwing. heartbeatHelper() dropped that response (its log
line was commented out) and insertEvent() logged it only at debug level,
so a watcher could lose every event for hours, for example while its
bucket is missing or after the datastore worker died, with nothing in
logcat to show it.

Log a warning for the first failed write of a run and, once a write to
the same bucket succeeds again, how many failed in between. Runs are
counted per bucket in one log for the whole process, like the datastore
itself, because the batch watchers build a new RustInterface on every
read. insertEvent() no longer logs every response at debug level, and
heartbeat() is declared nullable: the native side returns null when it
cannot build even its error object.
…omment

The comment said RustInterface construction and createBucketHelper()
make JNI/HTTP calls to an aw-server that may not be running yet at
boot. They never go through the HTTP server: the JNI calls open the
datastore in the app's own process. Say only that they can block for
seconds, which is why they run on the handlerThread, and leave the
reasons to the code that blocks.
@greptile-apps

greptile-apps Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no actionable issues were found.

Summary

Adds warning logs for failed datastore writes without logging every response.

  • Datastore write failures now show up in logcat by bucket.
  • The media watcher comment describes its local startup work without calling it HTTP.

No actionable issues were found. Tests were inspected but not run.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[heartbeatHelper or insertEvent] --> B[Native heartbeat response]
    B --> C[Shared WriteFailureLog]
    C --> D{Error or missing response?}
    D -->|Yes| E[Increase this bucket's failure count]
    E --> F[Warn only on first failure]
    D -->|No| G{Previous failures for this bucket?}
    G -->|Yes| H[Log recovery count and clear it]
    G -->|No| I[No log]
Loading

Reviews (1) · Last reviewed commit: "docs(media-watcher): drop the wrong HTTP..." · Reviewed by Greptile

@ErikBjare
ErikBjare merged commit c9a45e2 into ActivityWatch:master Oct 14, 2026
9 checks passed
@ThisIsLeoS
ThisIsLeoS deleted the fix/rust-log-write-errors branch October 14, 2026 22:39
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