Fractal Events
Fractal Events is event sourcing for the Fractal stack: events, a publisher that fans them out to projectors, an event store to keep them in, and the projectors that print them, persist them, or turn them back into commands.
Installation
pip install fractal-events
Background
An event says something already happened: this road was added. A command asks for something to happen. Keeping those apart is what makes the write side of an application replayable — events are facts, and facts can be stored, re-read and projected onto as many things as you like without any of those things knowing about each other.
That is what this package is: the fact, the fan-out, and somewhere to keep the facts.
Publishing
from fractal_events import EventPublisher, PrintEventProjector
publisher = EventPublisher([PrintEventProjector()])
publisher.publish_event(RoadAddedEvent(command=command, road_id="1"))
Events published together share one stream id; separate calls get separate ones. Every projector sees every event — the publisher does not filter, and projectors do not know about each other.
Projectors
PrintEventProjector— writes each event as one JSON line. Useful in development, and the cheapest possible audit trail.EventStoreProjector— commits each event to anEventStore.CommandBusProjector— maps events back onto commands, or onto Processes.
Mapping events back to commands
from fractal_events import CommandBusProjector, EventCommandMapper
class RebuildOnRoadAdded(EventCommandMapper):
def mappers(self):
return {RoadAddedEvent: [lambda e: RebuildCommand(road_id=e.road_id)]}
projector = CommandBusProjector(
lambda: context.command_bus,
[RebuildOnRoadAdded()],
)
Give this projector a lenient bus. Fan-out legitimately produces commands
this particular deployment has no handler for — that is normal, not broken. A
CommandBus() is strict and will raise; construct it as
CommandBus(strict=False) for a projector, so a miss is logged rather than
thrown. A strict bus is right for a service call, where a missing handler does
mean the application is wired wrong.
Mapping events to Processes
Process mappers run a stateful workflow instead of dispatching a command. They
need fractal-processes
(pip install fractal-processes), which is imported only when a process mapper
actually fires, and they need an application context:
projector = CommandBusProjector(
lambda: context.command_bus,
[],
process_mappers=[BuildRoadWorkflow()],
context_func=lambda: context,
)
context_func is injected rather than imported. The application context lives a
layer above this package, and importing it here would point the middle of the
stack at the top for one constructor call. Leaving it out while passing process
mappers raises at construction time, not on whichever event happens to arrive
first.
Event stores
Four flavours, differing only in how an event is stored and read back:
| store | stored as | needs |
|---|---|---|
ObjectEventStore |
the event object itself | an in-memory repository |
DictEventStore |
asdict(event) |
the event classes, to rebuild them |
JsonEventStore |
a JSON string | the event classes, plus an encoder |
PickleEventStore |
a pickle | — |
All of them take an EventStoreRepository, so where the messages actually land
is a fractal-repositories
concern rather than this package's.
Reading back an event whose class is no longer mapped raises
EventNotMappedError rather than skipping it — a gap in a replayed stream is
worse than a loud failure.
Development
make dev-install
make test
make lint
make format
Metadata
Release files for fractal-events 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| fractal_events-1.1.0.tar.gz | 16.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fractal_events-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.2 kB
Release files / fractal_events-1.1.0.tar.gz
| Download URL | fractal_events-1.1.0.tar.gz |
|---|---|
| Size | 16.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
48edbc31602578816240de4e4027097689d2ccb05753191c764cf41f7e2edb3f
|
|
BLAKE2b-256 checksum How to use checksums |
3336320ac50e1be08ea98011406d5452e9f782d5b98fc3921a76e21677d286b5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-requests/2.34.2
|
Release files / fractal_events-1.1.0-py3-none-any.whl
| Download URL | fractal_events-1.1.0-py3-none-any.whl |
|---|---|
| Size | 12.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8fbf3fd0015bdfd5e28675fb49461002c9ef584a703532f47d798b19b21c7395
|
|
BLAKE2b-256 checksum How to use checksums |
5859a96fd796479aa7c6efab722ba4829ad9c5c32fe1b7c8342eb1e1c45be239
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-requests/2.34.2
|
Security for fractal-events 1.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.