Skip to content

Conversation

Copy link

Copilot AI commented Jan 3, 2026

  • Update integration tests to match the new simplified API
    • Updated test_client_with_queue_batches_actions to use asyncio.create_task for concurrent execution
    • Updated test_client_manual_flush to start execution as a task before checking pending count
    • Updated test_client_close_flushes_queue to work with str return type instead of QueuedExecution
    • Updated test_client_queue_respects_max_actions to handle direct exec_id returns
    • All 15 queue-related tests now passing (10 unit tests + 5 integration tests)

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits January 3, 2026 18:52
…d enhance documentation

Co-authored-by: iMicknl <1424596+iMicknl@users.noreply.github.com>
…amples

Co-authored-by: iMicknl <1424596+iMicknl@users.noreply.github.com>
Copy link
Author

Copilot AI commented Jan 3, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • astral.sh
    • Triggering command: /usr/bin/curl curl -LsSf REDACTED (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title [WIP] Implement ActionQueue for batching actions in OverkizClient Fix concurrency issues and API safety in ActionQueue implementation Jan 3, 2026
Copilot AI requested a review from iMicknl January 3, 2026 18:54
@iMicknl
Copy link
Owner

iMicknl commented Jan 3, 2026

@copilot can you work around the different signatures and the need to await twice?

…str | QueuedExecution

Co-authored-by: iMicknl <1424596+iMicknl@users.noreply.github.com>
Copy link
Author

Copilot AI commented Jan 3, 2026

@copilot can you work around the different signatures and the need to await twice?

Fixed in commit 2dfbea4. The execute_action_group method now always returns str (exec_id) regardless of whether the queue is enabled. Users no longer need to handle different return types or await twice.

Before:

# Queue enabled - awkward double await
queued = await client.execute_action_group([action])
exec_id = await queued

After:

# Works the same with or without queue - single await
exec_id = await client.execute_action_group([action])

The batching still happens transparently in the background when the queue is enabled. The method internally awaits the QueuedExecution before returning the exec_id.

Copilot AI changed the title Fix concurrency issues and API safety in ActionQueue implementation Fix concurrency issues and simplify API in ActionQueue implementation Jan 3, 2026
@iMicknl
Copy link
Owner

iMicknl commented Jan 3, 2026

@copilot can you fix the linters? with pre-commit

Co-authored-by: iMicknl <1424596+iMicknl@users.noreply.github.com>
Copy link
Author

Copilot AI commented Jan 3, 2026

@copilot can you fix the linters? with pre-commit

Fixed in commit fb478b6. Ran pre-commit run --all-files and applied all formatting fixes:

✅ ruff (linter) - Passed
✅ ruff-format (formatter) - Fixed trailing whitespace and reformatted long lines
✅ mypy (type checker) - Passed
✅ All other pre-commit hooks - Passed

Note: The ty check hook fails because it requires uv which cannot be installed due to firewall restrictions, but this is not blocking as all other linters pass.

@iMicknl
Copy link
Owner

iMicknl commented Jan 3, 2026

@copilot please fix the tests as well!

Co-authored-by: iMicknl <1424596+iMicknl@users.noreply.github.com>
Copy link
Author

Copilot AI commented Jan 3, 2026

@copilot please fix the tests as well!

Fixed in commit 18baf42. Updated all integration tests to work with the simplified API where execute_action_group returns str directly instead of QueuedExecution.

Key changes:

  • Used asyncio.create_task() to start actions concurrently for batching tests
  • Removed double-await pattern (no longer needed)
  • All 15 queue-related tests now passing (10 unit tests + 5 integration tests)

@iMicknl iMicknl marked this pull request as ready for review January 3, 2026 21:30
@iMicknl iMicknl requested a review from tetienne as a code owner January 3, 2026 21:30
Copilot AI review requested due to automatic review settings January 3, 2026 21:30
@iMicknl iMicknl merged commit dab4dcb into v2/action_queue Jan 3, 2026
10 checks passed
@iMicknl iMicknl deleted the copilot/sub-pr-1866 branch January 3, 2026 21:34
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes concurrency issues in the ActionQueue implementation and simplifies the public API by making execute_action_group() consistently return an exec_id string instead of a QueuedExecution object when queueing is enabled.

Key changes:

  • Refactored flush logic into _prepare_flush() and _execute_batch() to execute batches outside the lock, preventing deadlocks
  • Simplified API: execute_action_group() now always returns str (awaits the QueuedExecution internally)
  • Added input validation for queue parameters in the client constructor
  • Updated all tests to use asyncio.create_task() for concurrent execution patterns

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pyoverkiz/action_queue.py Refactored flush logic to execute outside lock; added is_done() method; changed flush() return type to None; improved exception handling
pyoverkiz/client.py Simplified return type of execute_action_group() to always return str; added parameter validation for queue settings; updated documentation
tests/test_action_queue.py Updated tests to use is_done() instead of _future.done(); added proper task cleanup in awaitable test
tests/test_client_queue_integration.py Updated tests to use asyncio.create_task() for concurrent execution; adapted to new API returning str directly
test_queue_example.py Fixed spelling error; updated examples to match new API; example code needs fixes to properly demonstrate batching behavior
Comments suppressed due to low confidence (1)

pyoverkiz/action_queue.py:182

  • The flush task is cancelled here but the code does not wait for the cancellation to complete. This differs from the shutdown() method (lines 254-258) which properly waits for the cancelled task to finish. Not waiting for cancellation can lead to race conditions where the cancelled task might still be executing and holding references to waiters that have already been cleared from state.

Consider adding similar cancellation handling as in shutdown():

  • Store the task reference
  • Cancel it
  • Wait for the cancellation to complete using contextlib.suppress(asyncio.CancelledError)
        if self._flush_task and not self._flush_task.done():
            self._flush_task.cancel()
        self._flush_task = None

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 73 to +81
print("Queueing action 1...")
queued1 = await client.execute_action_group([action1])
print(f"Got QueuedExecution object: {queued1}")
exec_id1 = await client.execute_action_group([action1])
print(f"Got exec_id: {exec_id1}")

print("Queueing action 2...")
_queued2 = await client.execute_action_group([action2])
exec_id2 = await client.execute_action_group([action2])

print("Queueing action 3...")
_queued3 = await client.execute_action_group([action3])
exec_id3 = await client.execute_action_group([action3])
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example demonstrates sequential execution rather than batching. With the simplified API where execute_action_group awaits the result, each call blocks until the batch executes. Since the calls are sequential (awaited one at a time), each action will execute separately after the 0.5s delay, rather than batching together.

To properly demonstrate batching, the calls should be started concurrently using asyncio.create_task(), similar to the manual flush example (lines 114-128) and the integration tests. Otherwise, the actions will execute one at a time and won't be batched together, making the example misleading about the queue's batching capability.

Copilot uses AI. Check for mistakes.
_queued3 = await client.execute_action_group([action3])
exec_id3 = await client.execute_action_group([action3])

print(f"Pending actions in queue: {client.get_pending_actions_count()}")
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion will likely show 0 pending actions, not 3, because all three execute_action_group calls above have already been awaited sequentially. Each action was executed (after the 0.5s delay) before the next one was queued. The pending count check should be moved to before awaiting the results, similar to how it's done in the integration tests and manual flush example.

Copilot uses AI. Check for mistakes.
print(f"\nExec ID 1: {exec_id1}")
print(f"Exec ID 2: {exec_id2}")
print(f"Exec ID 3: {exec_id3}")
print(f"All same? {exec_id1 == exec_id2 == exec_id3}")
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comparison will likely evaluate to False because the three actions were executed sequentially (not batched together), so they would have different exec_ids from separate API calls. The actions only batch if they are queued concurrently within the delay window. Since each execute_action_group call was awaited before starting the next one, they executed as separate batches.

To make this comparison work as intended, the three execute_action_group calls should be started concurrently using asyncio.create_task() and then awaited together.

Copilot uses AI. Check for mistakes.
iMicknl added a commit that referenced this pull request Jan 3, 2026
…#1876)

- [x] Update integration tests to match the new simplified API
- Updated test_client_with_queue_batches_actions to use
asyncio.create_task for concurrent execution
- Updated test_client_manual_flush to start execution as a task before
checking pending count
- Updated test_client_close_flushes_queue to work with str return type
instead of QueuedExecution
- Updated test_client_queue_respects_max_actions to handle direct
exec_id returns
- All 15 queue-related tests now passing (10 unit tests + 5 integration
tests)

<!-- START COPILOT CODING AGENT TIPS -->
---

✨ Let Copilot coding agent [set things up for
you](https://github.com/iMicknl/python-overkiz-api/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot)
— coding agent works faster and does higher quality work when set up for
your repo.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: iMicknl <1424596+iMicknl@users.noreply.github.com>
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