Package: zeroeventhub
ZeroEventHubThis README file contains information specific to the Python port of the ZeroEventHub.
Please see themain readme filefor an overview of what this project is about.ClientWe recommend that you store the latest checkpoint/cursor for each partition in the client's
database. Example of simple single-partition consumption.Note about the example:Things starting with "my" is supplied by youThings starting with "their" is supplied by the service you connect to>>>importzeroeventhub>>>importhttpx>>>importasyncio>>>fromtypingimportSequence>>>fromunittest.mockimportMagicMock,Mock,PropertyMock>>>my_db=MagicMock()>>>my_person_event_repository=Mock()>>>my_person_event_repository.read_cursors_from_db.return_value=None# Step 1: Setup>>>their_partition_count=1# documented contract with server>>>their_service_url="https://localhost:8192/person/feed/v1">>>my_zeh_session=httpx.AsyncClient()# you can setup the authentication on the session>>>client=zeroeventhub.Client(their_service_url,their_partition_count,my_zeh_session)# Step 2: Load the cursors from last time we ran>>>cursors=my_person_event_repository.read_cursors_from_db()>>>ifnotcursors:...# we have never run before, so we can get all events with FIRST_CURSOR...# (if we just want to receive new events from now, we would use LAST_CURSOR)...cursors=[...zeroeventhub.Cursor(partition_id,zeroeventhub.FIRST_CURSOR)...forpartition_idinrange(their_partition_count)...]# Step 3: Enter listening loop...>>>my_still_want_to_read_events=PropertyMock(side_effect=[True,False])>>>asyncdefpoll_for_events(cursors:Sequence[zeroeventhub.Cursor])->None:...page_of_events=zeroeventhub.PageEventReceiver()...whilemy_still_want_to_read_events():...# Step 4: Use ZeroEventHub client to fetch the next page of events....awaitzeroeventhub.receive_events(page_of_events,...client.fetch_events(cursors),...)......# Step 5: Write the effect of changes to our own database and the updated...#         cursor value in the same transaction....withmy_db.begin_transaction()astx:...my_person_event_repository.write_effect_of_events_to_db(tx,page_of_events.events)...my_person_event_repository.write_cursors_to_db(tx,page_of_events.latest_checkpoints)...tx.commit()......cursors=page_of_events.latest_checkpoints...page_of_events.clear()>>>asyncio.run(poll_for_events(cursors))ServerThis library makes it easy to setup a zeroeventhub feed endpoint with FastAPI.>>>fromtypingimportAnnotated,Any,AsyncGenerator,Dict,Optional,Sequence>>>fromfastapiimportDepends,FastAPI,Request>>>fromfastapi.responsesimportStreamingResponse>>>fromzeroeventhubimport(...Cursor,...DataReader,...ZeroEventHubFastApiHandler,...)>>>fromunittest.mockimportMock>>>app=FastAPI()>>>PersonEventRepository=Mock>>>classPersonDataReader(DataReader):...def__init__(self,person_event_repository:PersonEventRepository)->None:...self._person_event_repository=person_event_repository......defget_data(...self,cursors:Sequence[Cursor],headers:Optional[Sequence[str]],page_size:Optional[int]...)->AsyncGenerator[Dict[str,Any],Any]:...return(...self._person_event_repository.get_events_since(cursors[0].cursor)....take(page_size)....with_headers(headers)...)>>>defget_person_data_reader()->PersonDataReader:...returnPersonDataReader(PersonEventRepository())>>>PersonDataReaderDependency=Annotated[...PersonDataReader,...Depends(get_person_data_reader,use_cache=True),...]>>>@app.get("person/feed/v1")...asyncdeffeed(request:Request,person_data_reader:PersonDataReaderDependency)->StreamingResponse:...api_handler=ZeroEventHubFastApiHandler(data_reader=person_data_reader,server_partition_count=1)...returnapi_handler.handle(request)DevelopmentTo run the test suite, assuming you already have Python 3.10 or later installed and on yourPATH:pipinstallpoetry==1.5.1
poetryconfigvirtualenvs.in-projecttruepoetryinstall--sync
poetryruncoveragerun--branch-mpytest
poetryruncoveragehtmlThen, you can open thehtmlcov/index.htmlfile in your browser to look at the code coverage report.Also, to pass the CI checks, you may want to run the following before pushing your changes:poetryrunblacktests/zeroeventhub/
poetryrunpylint./zeroeventhub/
poetryrunflake8
poetryrunmypy