Skip to content

feat: auto-convert Python objects that are passed to/from Queue Binding#123

Merged
ryanking13 merged 7 commits into
mainfrom
gyeongjae/queue-wrapper
Jun 17, 2026
Merged

feat: auto-convert Python objects that are passed to/from Queue Binding#123
ryanking13 merged 7 commits into
mainfrom
gyeongjae/queue-wrapper

Conversation

@ryanking13

Copy link
Copy Markdown
Contributor

Wrap Cloudflare Queue with our bindings wrapper so that users can see the native Python objects not JSProxies. By doing this, we can eliminate to_js and to_py when using Queue in Python workers.

While Queue is not our top priority, this is to remove to_js from our Python workers doc (https://developers.cloudflare.com/workers/languages/python/examples/#publish-to-a-queue)

@ask-bonk

ask-bonk Bot commented Jun 15, 2026

Copy link
Copy Markdown

Python 3.12+ -- the str | set[str] syntax is fine.

Now let me think about whether there are any actual bugs or issues:

  1. Potential issue with _convert_result and memoization: When batch.messages is accessed, _getattr_helper is called, and the result is memoized via setattr(self, "messages", result). Since messages is non-callable, _convert_result returns a list. On second access, the memoized list is returned. This is fine for the queue handler use case where messages are read once.

  2. Looking at _convert_result list handling more carefully: If python_from_rpc returns a list where items are still JsProxy, each gets wrapped in self.__class__(item). But self.__class__ is _BindingWrapper, so each message becomes a _BindingWrapper. Accessing message.body will then go through _getattr_helper, which calls python_from_rpc on the body value. This should correctly convert primitive values. Good.

  3. One potential concern: In _convert_result, the list handling wraps JsProxy items but passes through non-JsProxy items. But what about nested structures? If a list contains dicts that contain JsProxy values? Actually, python_from_rpc handles the .to_py() conversion first, so nested structures should already be converted. The list handling only catches cases where .to_py() leaves some items as JsProxy (which happens for complex objects like queue messages that have methods like ack()).

Let me verify there are no issues I'm missing. One thing I want to verify is that the _convert_result list handling won't cause issues for existing bindings like KV/R2/D1. Existing code only had the JsProxy -> self.__class__ branch. The new list branch is additive and only triggers when converted is a list. This should be safe for existing bindings.

Overall, this PR looks well-structured and follows established patterns. The code is clean, tests are comprehensive, and the approach of reusing _BindingWrapper for queues is consistent with how other bindings work.

There is one thing I notice: the test file has a pytestmark that skips all tests on Python < 3.13 with a FIXME comment about segfaults in dev environment. This is pre-existing context for this test approach. Not an issue introduced by this PR.

Let me check one more thing -- whether the consolidation of _BINDING_TYPES into a set and the corresponding _is_js_instance change is a purely behavioral-equivalent refactor:

Looking at the original code:

if _is_js_instance(binding, "KvNamespace"):
    return _BindingWrapper(binding)
if _is_js_instance(binding, "R2Bucket"):
    return _BindingWrapper(binding)
if _is_js_instance(binding, "D1Database"):
    return _BindingWrapper(binding)

New code:

_BINDING_TYPES = {"KvNamespace", "R2Bucket", "D1Database", "WorkerQueue"}
if _is_js_instance(binding, self._BINDING_TYPES):
    return _BindingWrapper(binding)

This is equivalent for the existing three types, plus adds WorkerQueue. Good.

After thorough review, I don't find any actionable issues -- no logic bugs, no security concerns, no backward compatibility problems, no missing error handling. The code follows established patterns, the refactoring is correct, and test coverage is solid.

LGTM

github run

@dom96 dom96 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

A few suggestions, but overall nice!

Comment thread packages/runtime-sdk/src/workers/_workers.py
Comment thread packages/runtime-sdk/src/workers/_workers.py
Comment thread packages/cli/tests/bindings-test/src/test_queue.py Outdated
Comment thread packages/cli/tests/bindings-test/src/test_queue.py Outdated
Comment thread packages/runtime-sdk/src/workers/_workers.py Outdated
@ryanking13 ryanking13 requested a review from hoodmane June 16, 2026 08:32
@ryanking13 ryanking13 merged commit 906a10a into main Jun 17, 2026
16 checks passed
@ryanking13 ryanking13 deleted the gyeongjae/queue-wrapper branch June 17, 2026 05:58
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.

3 participants