This module shows how event-sourced applications
</topics/application>
can be combined to make an event driven system.
this page is under development --- please check back soon
The library's system class...
from eventsourcing.system import System
from uuid import uuid4
from eventsourcing.domain import Aggregate, event
class Dog(Aggregate):
@event('Registered')
def __init__(self, name):
self.name = name
self.tricks = []
@event('TrickAdded')
def add_trick(self, trick):
self.tricks.append(trick)
Now let's define an application...
from eventsourcing.application import Application
class DogSchool(Application):
def register_dog(self, name):
dog = Dog(name)
self.save(dog)
return dog.id
def add_trick(self, dog_id, trick):
dog = self.repository.get(dog_id)
dog.add_trick(trick)
self.save(dog)
def get_dog(self, dog_id):
dog = self.repository.get(dog_id)
return {'name': dog.name, 'tricks': tuple(dog.tricks)}
Now let's define an analytics application...
from uuid import uuid5, NAMESPACE_URL
class Counter(Aggregate):
def __init__(self, name):
self.name = name
self.count = 0
@classmethod
def create_id(cls, name):
return uuid5(NAMESPACE_URL, f'/counters/{name}')
@event('Incremented')
def increment(self):
self.count += 1
from eventsourcing.application import AggregateNotFound
from eventsourcing.system import ProcessApplication
from eventsourcing.dispatch import singledispatchmethod
class Counters(ProcessApplication):
@singledispatchmethod
def policy(self, domain_event, process_event):
"""Default policy"""
@policy.register(Dog.TrickAdded)
def _(self, domain_event, process_event):
trick = domain_event.trick
try:
counter_id = Counter.create_id(trick)
counter = self.repository.get(counter_id)
except AggregateNotFound:
counter = Counter(trick)
counter.increment()
process_event.collect_events(counter)
def get_count(self, trick):
counter_id = Counter.create_id(trick)
try:
counter = self.repository.get(counter_id)
except AggregateNotFound:
return 0
return counter.count
system = System(pipes=[[DogSchool, Counters]])
from eventsourcing.system import SingleThreadedRunner
runner = SingleThreadedRunner(system)
runner.start()
school = runner.get(DogSchool)
counters = runner.get(Counters)
dog_id1 = school.register_dog('Billy')
dog_id2 = school.register_dog('Milly')
dog_id3 = school.register_dog('Scrappy')
school.add_trick(dog_id1, 'roll over')
school.add_trick(dog_id2, 'roll over')
school.add_trick(dog_id3, 'roll over')
assert counters.get_count('roll over') == 3
assert counters.get_count('fetch ball') == 0
assert counters.get_count('play dead') == 0
school.add_trick(dog_id1, 'fetch ball')
school.add_trick(dog_id2, 'fetch ball')
assert counters.get_count('roll over') == 3
assert counters.get_count('fetch ball') == 2
assert counters.get_count('play dead') == 0
school.add_trick(dog_id1, 'play dead')
assert counters.get_count('roll over') == 3
assert counters.get_count('fetch ball') == 2
assert counters.get_count('play dead') == 1
runner.stop()
from eventsourcing.system import MultiThreadedRunner
runner = MultiThreadedRunner(system)
runner.start()
school = runner.get(DogSchool)
counters = runner.get(Counters)
dog_id1 = school.register_dog('Billy')
dog_id2 = school.register_dog('Milly')
dog_id3 = school.register_dog('Scrappy')
school.add_trick(dog_id1, 'roll over')
school.add_trick(dog_id2, 'roll over')
school.add_trick(dog_id3, 'roll over')
school.add_trick(dog_id1, 'fetch ball')
school.add_trick(dog_id2, 'fetch ball')
school.add_trick(dog_id1, 'play dead')
from time import sleep
sleep(0.01)
assert counters.get_count('roll over') == 3
assert counters.get_count('fetch ball') == 2
assert counters.get_count('play dead') == 1
runner.stop()
eventsourcing.system