Skip to content

fix(queue): warn before connect and create buckets immediately#112

Merged
ErikBjare merged 3 commits into
ActivityWatch:masterfrom
TimeToBuildBob:bob/issue-37-queued-create-bucket
Jun 29, 2026
Merged

fix(queue): warn before connect and create buckets immediately#112
ErikBjare merged 3 commits into
ActivityWatch:masterfrom
TimeToBuildBob:bob/issue-37-queued-create-bucket

Conversation

@TimeToBuildBob

Copy link
Copy Markdown
Contributor

Fixes #37

This makes the queued bucket path less misleading in two ways:

  • warn once when queued=True is used before connect() or with client: starts the request queue
  • create queued buckets immediately when they are registered after the queue is already connected

Verification:

  • .venv/bin/python -m pytest -q tests/test_requestqueue.py tests/test_client.py -k "register_bucket or queued_usage_warns_once_before_connect"
  • ruff check aw_client/client.py tests/test_requestqueue.py tests/test_client.py

@greptile-apps

greptile-apps Bot commented Jun 7, 2026

Copy link
Copy Markdown

Greptile Summary

This PR improves the developer experience of the queued-bucket path by issuing a one-time UserWarning when queued operations are used before connect() is called, and by eagerly creating buckets on the server immediately when they are registered while the queue thread is already connected.

  • _warn_queue_before_connect() is added to ActivityWatchClient and called from create_bucket(queued=True) and heartbeat(queued=True); the flag is correctly reset in disconnect() so the warning fires again after a reconnect cycle.
  • RequestQueue.register_bucket() now calls client.create_bucket() immediately when self.connected is True, catching RequestException and marking the queue disconnected on failure; the corresponding unit tests verify both the happy path and the failure path.

Confidence Score: 5/5

The change is safe to merge: it adds opt-in warning behaviour and an eager bucket-create on an already-connected queue, both guarded by existing exception handling and covered by new unit tests.

Both new behaviours (the one-shot warning and the eager create_bucket call in register_bucket) are narrowly scoped, the error path in register_bucket correctly resets connected, and disconnect() properly resets the warning flag so the warning fires again after a reconnect cycle. The previous concern about the flag not being reset in disconnect() is addressed in this PR.

No files require special attention.

Important Files Changed

Filename Overview
aw_client/client.py Adds _warn_queue_before_connect() helper with correct stacklevel for direct callers, disconnect() now resets the warning flag, and register_bucket eagerly creates buckets when already connected. Logic is sound; see note on stacklevel for the deprecated setup_bucket path.
tests/test_client.py Adds test_queued_usage_warns_once_before_connect which correctly verifies exactly one warning is emitted across two queued calls made before connect().
tests/test_requestqueue.py Adds MockClient.create_bucket_calls tracking and two new tests for the eager-create behaviour: happy path and ConnectionError failure path. Both tests are well-scoped unit tests.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User
    participant Client as ActivityWatchClient
    participant Queue as RequestQueue
    participant Server as aw-server

    Note over User,Server: Scenario A — queued ops before connect()
    User->>Client: "create_bucket(queued=True)"
    Client->>Client: "_warn_queue_before_connect()<br/>[is_alive()=False → emit UserWarning]"
    Client->>Queue: register_bucket()
    Note right of Queue: connected=False → only append to _registered_buckets

    User->>Client: "heartbeat(queued=True)"
    Client->>Client: "_warn_queue_before_connect()<br/>[_warned=True → skip]"

    User->>Client: connect()
    Client->>Queue: start()
    Queue->>Queue: _try_connect() → _create_buckets()
    Queue->>Client: "create_bucket() [queued=False]"
    Client->>Server: POST /api/0/buckets/b
    Queue->>Queue: "connected = True"

    Note over User,Server: Scenario B — register_bucket after connect()
    User->>Client: "create_bucket(queued=True)"
    Client->>Client: "_warn_queue_before_connect()<br/>[is_alive()=True → skip]"
    Client->>Queue: register_bucket()
    Note right of Queue: connected=True → eager create
    Queue->>Client: "create_bucket() [queued=False]"
    Client->>Server: POST /api/0/buckets/b2
    alt RequestException
        Server-->>Queue: raise RequestException
        Queue->>Queue: "connected = False"
    else success
        Server-->>Client: 200
    end

    User->>Client: disconnect()
    Client->>Queue: stop() + join()
    Client->>Client: "_warned_queue_before_connect = False"
    Client->>Queue: new RequestQueue()
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User
    participant Client as ActivityWatchClient
    participant Queue as RequestQueue
    participant Server as aw-server

    Note over User,Server: Scenario A — queued ops before connect()
    User->>Client: "create_bucket(queued=True)"
    Client->>Client: "_warn_queue_before_connect()<br/>[is_alive()=False → emit UserWarning]"
    Client->>Queue: register_bucket()
    Note right of Queue: connected=False → only append to _registered_buckets

    User->>Client: "heartbeat(queued=True)"
    Client->>Client: "_warn_queue_before_connect()<br/>[_warned=True → skip]"

    User->>Client: connect()
    Client->>Queue: start()
    Queue->>Queue: _try_connect() → _create_buckets()
    Queue->>Client: "create_bucket() [queued=False]"
    Client->>Server: POST /api/0/buckets/b
    Queue->>Queue: "connected = True"

    Note over User,Server: Scenario B — register_bucket after connect()
    User->>Client: "create_bucket(queued=True)"
    Client->>Client: "_warn_queue_before_connect()<br/>[is_alive()=True → skip]"
    Client->>Queue: register_bucket()
    Note right of Queue: connected=True → eager create
    Queue->>Client: "create_bucket() [queued=False]"
    Client->>Server: POST /api/0/buckets/b2
    alt RequestException
        Server-->>Queue: raise RequestException
        Queue->>Queue: "connected = False"
    else success
        Server-->>Client: 200
    end

    User->>Client: disconnect()
    Client->>Queue: stop() + join()
    Client->>Client: "_warned_queue_before_connect = False"
    Client->>Queue: new RequestQueue()
Loading

Reviews (2): Last reviewed commit: "fix(queue): reset warn flag in disconnec..." | Re-trigger Greptile

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

@greptileai review

@TimeToBuildBob

Copy link
Copy Markdown
Contributor Author

Addressed the Greptile 4/5 finding: _warned_queue_before_connect was never reset in disconnect(), so after a connect→disconnect cycle the warn-before-connect guard would stay True permanently — silencing the warning even though the new RequestQueue isn't running yet.

Fix: add self._warned_queue_before_connect = False in disconnect() alongside the existing self.request_queue = RequestQueue(self) reset, so the warning fires correctly after reconnect.

Re-triggered Greptile review on the updated commit.

@ErikBjare ErikBjare merged commit b2ddb46 into ActivityWatch:master Jun 29, 2026
7 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.

Cannot create_bucket with queued=True

2 participants