Repository navigation
Conversation
- Add python-solace-connection-config.py plus guaranteed and direct publisher and subscriber samples under references/python, derived from the Solace Python samples and elevated to the Python developer guide and C API best practices - Register service listeners before connect(), use a 3000 ms reconnect interval, pair reject back pressure with a readiness listener, check publish receipts, subscribe the CREATE_ON_START queue to the topic, client-ack after processing, and shut down gracefully on SIGINT and SIGTERM - Read config.json or command-line arguments through the shared helper, mirroring jcsmp-solace-connection-config.java, with no version pin - Reword JCSMP sample comments to drop the legacy product name and the comparisons to upstream samples - Verify locally against solace-pubsubplus resolved from PyPI with a no-broker smoke test and live round trips per pair
- Drop `from __future__ import annotations` and its explanatory comment from the five Python reference samples - The built-in generics in the signatures run natively on every Python release that Solace supports, so the shim added nothing - Match the upstream SolaceSamples/solace-samples-python style, which carries no future import - Verified: all five modules import with solace-pubsubplus installed
- Replace the ten-line HA and replication comment with a five-line HA-only comment that mirrors the JCSMP sample - List the C API Best Practices values as Python API calls: connection and reconnection retry strategies plus the CONNECTION_RETRIES_PER_HOST transport property - Drop the replication guidance, the forever_retry remark, and the comma-separated host list - Shorten the back pressure comment above PUBLISH_BUFFER_CAPACITY to one line in both publisher samples
- Shorten the module docstring of python-solace-connection-config.py while keeping every contract point (key names, pass-through, override order, gitignore rule, empty-password handling) - Move the AI-assisted code header block to the end of the docstring to match the other Python samples
- Add a job-level `if: false` to trigger-evals: no policy permits an API key on this public repo, so the job could only self-skip and asserted nothing - Keep the job definition so it can be re-enabled by removing the `if` once a key is allowed; trigger evals continue to run locally
- Add __pycache__/ to .gitignore so byte-compiling the Python reference samples leaves no untracked files
- Register the SIGINT/SIGTERM handlers before setup_solace(), so a SIGTERM during the blocking connect() still reaches teardown instead of killing the process - Return exit code 1 from every failure exit (failed queue bind, service interruption, receiver termination, publish() failure); main() now returns the code and __main__ passes it to sys.exit() - Correct the guaranteed subscriber's terminate() comments: the receiver turns TERMINATED once its buffer is empty, so the ack() of the message still in the handler can fail and the message is redelivered - Verified against a live broker: both round trips exit 0, and the bind failure, a service interruption (reconnect exhausted), and SIGTERM during connect each run teardown and exit 1
- Describe why the samples bound terminate(): a predictable shutdown time, for example within a process supervisor's stop timeout, so the disconnect still runs - State the API default (600000 ms) as a fact and invite adjusting the value to suit the application
- Name MessageDestinationDoesNotExistError for the no-subscription-match NACK, matching the library's subcode mapping - Drop "a broker rejection" from the direct publisher failure listener comment; broker events never reach that listener - Split terminate() handling into IncompleteMessageDeliveryError and other client errors, and exit non-zero on both - Update the exit_code comments to match, and drop the inaccurate "failed bind" case in the guaranteed subscriber - Describe the disabled trigger-evals CI job in the evals README and point to local runs - Include *.py in the link check so the Python sample header URLs are swept
- Use the claude CLI aliases (sonnet, opus) in the run examples so they always select the latest model in each family - Describe the runner defaults, the CI matrix, and the judge by model family instead of pinned IDs - Remove the stale claude-opus-5 reference
|
Just a general question - do we have any automated regression that can detect when your code examples become stale with product? For example, a function becomes deprecated, args change, name change, etc is there something that alerts us that samples need to be re-worked? Also this is more of an edge case but what about when a customer uses the skill gets something half done but then the api updates and breaks existing code - is there anything that helps update their code automatically? |
Right now we have a However, the
There is nothing in place to update their code automatically, I also am not sure what mechanism would do that. I can say though that when a user begins developing with the skill for JCSMP, the skill will pull the latest JCSMP off of maven central and then pin that version in the pom file. So if the next release after that was a major version bump, I would hope that Claude would be smart enough to flag the version to be the problem if there were issues. |
mtite-sol
left a comment
There was a problem hiding this comment.
Added some non-blocking questions / comments but otherwise LGTM!
Good to know we already have a compile-check as part of CI that should help to solve most cases! Could be worth augmenting it to detect deprecation warnings though so we don't lag on giving customers best practices. For the updating code automatically comment might just be something to test later to see if Claude's able to resolve conflicts like that automatically. It might be a non-issue. |
- Replace the Java-style app classes with module-level functions (main, setup_solace, run_publish_loop or await_messages, teardown_solace) that share one dataclass state - Keep the listener classes, since the Python API requires listener subclasses; they now take the shared state - Replace the SolaceConnectionConfig class with one load_service_properties() function that returns the from_properties() dict - Use X | None type hints for the Python 3.10+ floor - Publishers: on_back_pressure_wait(50) replaces on_back_pressure_reject(1000), so the readiness listener and the PublisherOverflowError retry are removed - Direct subscriber: bound the receive buffer with on_back_pressure_drop_latest(50) - Verified with the smoke test, both live round trips, and a frozen-proxy test of a blocked publish() (returns on drain, or raises after the reconnect budget)
- setup_solace() now builds the service and the publisher or receiver before any connection exists, and returns a fully populated state, so no state object is created empty and filled in later (no | None fields) - New connect_solace() connects the service and starts the endpoint; main() calls setup_solace() before its try and runs teardown in finally - Remove the reconnect pause from both publishers: a guaranteed publish waits in the buffer during a reconnect, and the direct publisher now documents that messages published during a reconnect are lost and reported through the publish failure listener, pointing to guaranteed messaging for lossless delivery - Raise the back pressure buffer from 50 to 1000, the value the Python developer guide uses in its examples (the API has no default capacity), and note that it counts messages and is tunable to deployment memory
… ones - Direct publisher passes the payload straight to publish() with no OutboundMessageBuilder, and shows additional_message_properties for per-message headers; a comment notes the builder suits "templated" messages with many fixed headers - Guaranteed publisher uses the builder as a template: the time-to-live (new MESSAGE_TTL_MS, 60 s) is set once, since build() copies the template into each message, and the per-message application message id goes through build()'s additional_message_properties so it never changes the template
- Remove APPROX_MSG_RATE_PER_SEC and the delay after each send from the Python and JCSMP direct and guaranteed publisher samples, so the loop publishes as fast as send() or publish() returns, the way an application publishes each message as soon as it has one - Update the demo-harness rule in implement-mode.md: the continuous publish loop replaces the pacing Thread.sleep in the list, and generated applications never add a delay or rate limit between sends that the application does not ask for - Output evals not run for the implement-mode.md change
- Set the reconnection retry strategy before from_properties() in all four samples: the builder merges calls in order and a later call wins, so the code's strategy is now a default that reconnection keys in the properties (for example config.json) override; update the connection config helper docstring to match - Load the Solace properties in main() and pass them to setup_solace(), so converting the application's input (config.json or argv) stays out of the Solace setup - Log a buffered-message loss at direct publisher shutdown as a warning and keep exit code 0, since direct (at-most-once) messaging allows it
|
|
||
|
|
||
| def run_publish_loop(state: PublisherState) -> None: | ||
| threading.Thread(target=print_stats, args=(state,), name="stats", daemon=True).start() |
There was a problem hiding this comment.
Might be a nick pick but, shouldn't this thread get joined? the daemon thread mean its only cleaned up on system exit.
- Call receive_async() before receiver.start() in both subscriber samples, so the handler is in place when delivery begins and messages do not wait in the API buffer - Keep receive_async() after connect(), since _can_receive_message() requires a connected service - Address PR #8 review comment on the guaranteed subscriber sample
- Rename the four Python samples to python-<delivery>-<role>-async-sample.py - Update the generated project file names to match, for example guaranteed_subscriber_async.py - Use the async/sync terms from the Python developer guide, so later sync samples (publish_await_acknowledgement, receive_message) fit the scheme - Add guidance to the guaranteed publisher on how to choose the message TTL: at least the longest consumer recovery time (restart plus reconnect), or a multiple of it
What is the purpose of this change?
Python equivalent of the JCSMP pub/sub reference samples. The
solace-application-developmentskill gets four baked Python pattern samples plus a shared connection helper underreferences/python/, so a follow-up story can route Python requests to real, complete, idiomatic code instead of code written from memory. Skill routing, mode files, the description, and eval cases are out of scope here and follow in separate stories.How is this accomplished?
python-solace-connection-config.py: reads a gitignoredconfig.jsonwhose keys are Python API property-name strings (generic pass-through tofrom_properties()), or falls back to<host:port> <message-vpn> <client-username> [password]. It always supplies the basic-auth password key, which the API requires atbuild().python-guaranteed-publisher-sample.py,python-guaranteed-subscriber-sample.py,python-direct-publisher-sample.py, andpython-direct-subscriber-sample.py, derived from thepatterns/files of the Solace Python samples and structured like the JCSMP samples:setup_solace(), a run loop, andteardown_solace()frommain'sfinally.connect(),on_back_pressure_rejectpaired with aPublisherReadinessListener, a publish receipt listener that checks the receipt exception and correlates byuser_context, aPublishFailureListeneron the direct publisher,CREATE_ON_STARTpluswith_subscriptions()so the provisioned queue attracts messages, explicit client ack after processing, and gracefulterminate()thendisconnect()on SIGINT and SIGTERM.Also disabled trigger evals from running in CI since we dont have a repo secret for Anthropic API Key.
Anything reviewers should focus on/be aware of?
localhost; every listener class instantiated; a non-UTF-8 payload still acknowledged) and live publisher to subscriber round trips per pair against a local software broker container. Both pairs delivered all 26 rotating payload letters with no warnings, the queue was empty afterwards, and publish receipts arrived correlated by message id. The drivers are not part of this PR; they belong to the Python verify story.compile-checkstill covers the JCSMP comment edits.