Report failures and share a database - #6
Merged
Conversation
The fold layer has always understood `failure` and `revert_failure` and the persistence datasource has always filled them in, but the listener never emitted either. Watching a running engine told a client that an atom reached FAILURE and nothing more, while reading the same run out of persistence told it why -- so which producer you were attached to changed the answer, which is exactly what this package is supposed to hide. The listener has the `Failure` in hand: taskflow hands it over as the atom's result on the very notification that carries the state. It now renders it, in the same shape persistence reports, because the renderer is one function that both call. `_failure_dict` moved out of the persistence datasource into `models.failure_dict` for that reason -- two renderers agreeing by inspection is not the same as one shape. Which of the two keys it lands under follows from the state rather than from the intention. Taskflow does not put an intention on these notifications, and only a revert that itself failed reaches REVERT_FAILURE, so the state is the whole of the information needed. 838 tests pass, including a flow whose task raises and whose snapshot now carries the exception type and message. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`attach()` reported every run as being called "". The in-process producer emits FLOW_STRUCTURE once, before anything runs, precisely because taskflow never persists the edges -- so that is the event a run gets seeded from, and it carries no flow name. The FLOW_STATE events that follow do carry one, and fold was throwing it away: it replaced the state and nothing else. It now takes the name from whichever event has one, keeping what it already holds otherwise. That leaves the persistence path unchanged, where the first event seen is a state event and the name was never in doubt, and fixes the path where it was. 838 tests pass, with an integration test that names a flow and reads the name back out of a snapshot seeded by the graph. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This package is meant to be co-installed into a service, and a deployment that puts the store in that service's database ends up with two alembic trees in one schema. Both kept their revision in `alembic_version`, so each read the other's revision as one it had never heard of: the host's migrations fail against the store's revision, or the store's against the host's, depending on who runs first. `upgrade()` now takes a `version_table`, passed through the alembic config to both the offline and online paths. Nothing changes for a deployment with a database of its own, which is why the default stays `alembic_version` rather than something namespaced -- a database already migrated under the old name keeps working untouched. The docstring says the one thing that can go wrong afterwards: the name has to be the same on every upgrade of a given database, because pointing alembic at an empty table looks exactly like a database that was never migrated. 838 tests pass, including one that upgrades into a named table, checks `alembic_version` was never created, and upgrades again to confirm idempotence against the table it was given. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The same argument as the dependency floors, one level down: this package is co-installed into a service that has already chosen its interpreter, so requiring 3.11 rules out hosts that are otherwise perfectly able to run it -- Ubuntu 22.04 ships 3.10, and a good deal of OpenStack still runs there. Nothing in the package needed 3.11. Two spellings did. `typing.Self` was the return type of four `__enter__` methods and one classmethod. Each is now a `TypeVar` bound to its own class, which is how the same thing was written before 3.11 and which mypy strict checks identically. `enum.StrEnum` is imported where it exists and falls back to a `str, Enum` mixin whose `__str__` returns the value: the plain mixin renders as `EventKind.FLOW_STATE`, and the value is what goes on the wire. Then running the suite on 3.10 found a bug, which is what running it is for. The sleep between SSE polls suppresses `TimeoutError` around `asyncio.wait_for`, and on 3.10 `asyncio.TimeoutError` is a class of its own rather than the builtin -- so the suppression caught nothing and the stream raised out of its own sleep at the first quiet interval. Four tests fail on 3.10 and pass on every other version, which is the shape a bug takes when the matrix does not cover the floor. CI gains 3.10 in the test and conformance matrices, and the lowest-direct job moves there, since it exists to install the oldest releases on the oldest interpreter supported. 838 tests pass on 3.10, 3.12 and 3.14, and on 3.10 with every declared floor installed exactly -- taskflow 4.2.0, oslo.config 6.9.0, SQLAlchemy 1.4.0, alembic 1.2.0, kombu 5.1.0, oslo.messaging 6.0.0. Lint, format, hacking and mypy all pass with mypy targeting 3.10. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Five badges, each answering a question somebody arriving at the repository asks before reading any prose: are the tests passing, do the host frameworks still agree, what is released, what does it run on, and under what licence. No coverage badge, because nothing publishes coverage to a service that could back one -- CI keeps the report as an artifact, and a badge for a number nobody can check is worse than none. The licence badge links to `LICENSE` the way the rest of the README links to `docs/` and `CHANGELOG.md`, rather than being the one absolute link on the page. While confirming those links resolve, the project URLs turned out not to. Every one of them -- Homepage, Source, Issues, Changelog -- pointed at github.com/daipham3213/taskflow-meter, which is the PyPI name and 404s; the repository is taskflow.meter. That is four dead links on the PyPI page of the released version, including the one PyPI's trusted publishing matches on. Checked rather than assumed: all five badge images render (ci passing, conformance passing, pypi v1.1.0, python 3.11-3.14, Apache-2.0), the repository URL answers 200 and the old one 404, and `twine check` passes on both artifacts, since the README is also the long description. The Python badge reads 3.11-3.14 until the next release, which is what 1.1.0 supports; 3.10 is in the metadata and will show once that ships. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.