ergon-framework-python 0.1.8__tar.gz → 0.1.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/PKG-INFO +1 -1
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/pyproject.toml +2 -2
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/__init__.py +1 -1
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/mixins/consumer.py +146 -7
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/policies.py +10 -1
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon_framework_python.egg-info/PKG-INFO +1 -1
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/tests/test_smoke.py +1 -1
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/LICENSE +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/README.md +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/setup.cfg +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/_observability/docker-compose.telemetry.yml +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/_observability/grafana.yaml +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/_observability/loki.yaml +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/_observability/otel-collector-config.yaml +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/_observability/prometheus.yaml +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/_observability/tempo.yaml +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/connectors/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/main.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/tasks/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/tasks/constants.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/tasks/example_task/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/tasks/example_task/config.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/tasks/example_task/exceptions.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/tasks/example_task/helpers.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/tasks/example_task/schemas.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/tasks/example_task/task.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/tasks/exceptions.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/tasks/helpers.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/tasks/schemas.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/bootstrap/src/__project__/tasks/settings.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/cli.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/ergon_platform/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/ergon_platform/_client.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/ergon_platform/_operations.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/ergon_platform/async_connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/ergon_platform/connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/ergon_platform/models.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/ergon_platform/utils.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/excel/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/excel/connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/excel/models.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/excel/service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/async_auth_service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/async_connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/async_service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/auth_service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/models.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/utils.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/pipefy/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/pipefy/async_connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/pipefy/async_service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/pipefy/connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/pipefy/models.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/pipefy/service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/pipefy/version.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/postgres/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/postgres/async_connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/postgres/async_service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/postgres/models.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/rabbitmq/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/rabbitmq/async_connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/rabbitmq/async_service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/rabbitmq/connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/rabbitmq/helper.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/rabbitmq/models.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/rabbitmq/service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/sqs/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/sqs/async_connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/sqs/async_service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/sqs/connector.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/sqs/models.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/sqs/service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/transaction.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/py.typed +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/service/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/service/service.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/base.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/exceptions.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/helpers.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/liveness.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/manager.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/mixins/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/mixins/metrics.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/mixins/producer.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/runner.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/utils.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/telemetry/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/telemetry/_resource.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/telemetry/logging.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/telemetry/metrics.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/telemetry/tracing.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/utils/__init__.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/utils/env.py +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon_framework_python.egg-info/SOURCES.txt +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon_framework_python.egg-info/dependency_links.txt +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon_framework_python.egg-info/entry_points.txt +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon_framework_python.egg-info/requires.txt +0 -0
- {ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon_framework_python.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ergon-framework-python"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.9"
|
|
4
4
|
description = "Ergon internal task-oriented project bootstrapper"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -47,7 +47,7 @@ dev = [
|
|
|
47
47
|
"pyright>=1.1.390",
|
|
48
48
|
"pytest>=8.0.0",
|
|
49
49
|
"pytest-asyncio>=0.25.0",
|
|
50
|
-
"ruff>=0.6.0",
|
|
50
|
+
"ruff>=0.6.0,<0.16",
|
|
51
51
|
]
|
|
52
52
|
|
|
53
53
|
[build-system]
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/mixins/consumer.py
RENAMED
|
@@ -601,22 +601,28 @@ class AsyncConsumerMixin(ABC):
|
|
|
601
601
|
# =====================================================================
|
|
602
602
|
# FETCH HANDLER (ASYNC)
|
|
603
603
|
# =====================================================================
|
|
604
|
-
async def _handle_fetch(
|
|
604
|
+
async def _handle_fetch(
|
|
605
|
+
self,
|
|
606
|
+
conn,
|
|
607
|
+
policy: policies.FetchPolicy,
|
|
608
|
+
batch_size: int | None = None,
|
|
609
|
+
) -> tuple[bool, List[connector.Transaction]]:
|
|
610
|
+
fetch_size = policy.batch.size if batch_size is None else batch_size
|
|
605
611
|
self._mark_consumer_progress("fetching")
|
|
606
|
-
logger.info(f"Fetch handler started for batch size {
|
|
612
|
+
logger.info(f"Fetch handler started for batch size {fetch_size}", extra=policy.extra)
|
|
607
613
|
fetch_start = time.perf_counter()
|
|
608
614
|
success, result = await helpers.run_fn_async(
|
|
609
|
-
fn=lambda: conn.fetch_transactions_async(
|
|
615
|
+
fn=lambda: conn.fetch_transactions_async(fetch_size, **policy.extra),
|
|
610
616
|
retry=policy.retry,
|
|
611
617
|
trace_name=f"{self.__class__.__name__}.fetch_transactions",
|
|
612
|
-
trace_attrs={"batch_size":
|
|
618
|
+
trace_attrs={"batch_size": fetch_size},
|
|
613
619
|
)
|
|
614
620
|
# Record fetch metrics
|
|
615
621
|
fetched_count = len(result) if success and result else 0
|
|
616
622
|
mixin_metrics.record_consumer_fetch(
|
|
617
623
|
task_name=getattr(self, "name", self.__class__.__name__),
|
|
618
624
|
connector_name=conn.__class__.__name__,
|
|
619
|
-
batch_size=
|
|
625
|
+
batch_size=fetch_size,
|
|
620
626
|
fetched_count=fetched_count,
|
|
621
627
|
duration=time.perf_counter() - fetch_start,
|
|
622
628
|
success=success,
|
|
@@ -877,13 +883,146 @@ class AsyncConsumerMixin(ABC):
|
|
|
877
883
|
)
|
|
878
884
|
return await self._handle_exception(tr, timeout_error, pol.exception.retry)
|
|
879
885
|
|
|
886
|
+
async def _consume_continuous():
|
|
887
|
+
nonlocal batch_number, empty_count, processed
|
|
888
|
+
|
|
889
|
+
concurrency = policy.loop.concurrency.value
|
|
890
|
+
submitted = 0
|
|
891
|
+
in_flight: set[asyncio.Task] = set()
|
|
892
|
+
|
|
893
|
+
async def reap(done: set[asyncio.Task]) -> None:
|
|
894
|
+
nonlocal processed
|
|
895
|
+
for task in done:
|
|
896
|
+
try:
|
|
897
|
+
await task
|
|
898
|
+
except Exception as exc:
|
|
899
|
+
logger.error("[async] Execution error: %s", exc)
|
|
900
|
+
finally:
|
|
901
|
+
processed += 1
|
|
902
|
+
|
|
903
|
+
async def wait_for_completion() -> None:
|
|
904
|
+
done, _ = await asyncio.wait(
|
|
905
|
+
in_flight,
|
|
906
|
+
return_when=asyncio.FIRST_COMPLETED,
|
|
907
|
+
)
|
|
908
|
+
in_flight.difference_update(done)
|
|
909
|
+
await reap(done)
|
|
910
|
+
self._mark_consumer_progress("polling")
|
|
911
|
+
|
|
912
|
+
try:
|
|
913
|
+
while True:
|
|
914
|
+
if policy.loop.limit is not None and submitted >= policy.loop.limit:
|
|
915
|
+
if in_flight:
|
|
916
|
+
await wait_for_completion()
|
|
917
|
+
continue
|
|
918
|
+
break
|
|
919
|
+
|
|
920
|
+
free_slots = concurrency - len(in_flight)
|
|
921
|
+
if free_slots == 0:
|
|
922
|
+
await wait_for_completion()
|
|
923
|
+
continue
|
|
924
|
+
|
|
925
|
+
if policy.loop.limit is not None:
|
|
926
|
+
free_slots = min(free_slots, policy.loop.limit - submitted)
|
|
927
|
+
|
|
928
|
+
logger.debug(
|
|
929
|
+
"Fetching transactions for %d free continuous-consumer slot(s) with fetch policy: %s",
|
|
930
|
+
free_slots,
|
|
931
|
+
policy.fetch.model_dump_json(indent=2),
|
|
932
|
+
)
|
|
933
|
+
success, result = await self._handle_fetch(
|
|
934
|
+
conn,
|
|
935
|
+
policy.fetch,
|
|
936
|
+
batch_size=free_slots,
|
|
937
|
+
)
|
|
938
|
+
|
|
939
|
+
if not success:
|
|
940
|
+
logger.error("Fetch failed → %s", result)
|
|
941
|
+
# Unlike shutdown/cancellation, a fetch failure must not
|
|
942
|
+
# cancel work already in progress: let in-flight
|
|
943
|
+
# transactions finish (bounded by the transaction
|
|
944
|
+
# runtime timeout) before propagating the failure.
|
|
945
|
+
if in_flight:
|
|
946
|
+
logger.warning(
|
|
947
|
+
"Fetch failed with %d transaction(s) in flight; draining before raising",
|
|
948
|
+
len(in_flight),
|
|
949
|
+
)
|
|
950
|
+
await asyncio.gather(*in_flight, return_exceptions=True)
|
|
951
|
+
in_flight.clear()
|
|
952
|
+
if isinstance(result, (asyncio.TimeoutError, futures.TimeoutError)):
|
|
953
|
+
raise exceptions.FetchTimeoutException(str(result))
|
|
954
|
+
raise exceptions.FetchException(str(result))
|
|
955
|
+
|
|
956
|
+
transactions = result
|
|
957
|
+
if transactions:
|
|
958
|
+
empty_count = 0
|
|
959
|
+
batch_number += 1
|
|
960
|
+
self._mark_consumer_progress("processing")
|
|
961
|
+
logger.info(
|
|
962
|
+
"%d transaction(s) fetched for continuous processing",
|
|
963
|
+
len(transactions),
|
|
964
|
+
)
|
|
965
|
+
mixin_metrics.record_consumer_batch(
|
|
966
|
+
task_name=getattr(self, "name", self.__class__.__name__),
|
|
967
|
+
batch_number=batch_number,
|
|
968
|
+
batch_size=len(transactions),
|
|
969
|
+
streaming=policy.loop.streaming,
|
|
970
|
+
)
|
|
971
|
+
for transaction in transactions:
|
|
972
|
+
in_flight.add(
|
|
973
|
+
asyncio.create_task(
|
|
974
|
+
submit_start_processing(transaction, policy),
|
|
975
|
+
)
|
|
976
|
+
)
|
|
977
|
+
submitted += 1
|
|
978
|
+
continue
|
|
979
|
+
|
|
980
|
+
if in_flight:
|
|
981
|
+
await wait_for_completion()
|
|
982
|
+
continue
|
|
983
|
+
|
|
984
|
+
self._mark_consumer_progress("idle")
|
|
985
|
+
logger.info("Empty fetch detected at %s", datetime.now().isoformat())
|
|
986
|
+
if not policy.loop.streaming:
|
|
987
|
+
logger.info("Non-streaming mode detected, breaking loop")
|
|
988
|
+
break
|
|
989
|
+
|
|
990
|
+
mixin_metrics.record_consumer_empty_queue_wait(
|
|
991
|
+
task_name=getattr(self, "name", self.__class__.__name__),
|
|
992
|
+
wait_count=empty_count,
|
|
993
|
+
)
|
|
994
|
+
await utils.backoff_async(
|
|
995
|
+
backoff=policy.fetch.empty.backoff,
|
|
996
|
+
multiplier=policy.fetch.empty.backoff_multiplier,
|
|
997
|
+
cap=policy.fetch.empty.backoff_cap,
|
|
998
|
+
attempt=empty_count,
|
|
999
|
+
)
|
|
1000
|
+
empty_count += 1
|
|
1001
|
+
except BaseException:
|
|
1002
|
+
for task in in_flight:
|
|
1003
|
+
task.cancel()
|
|
1004
|
+
if in_flight:
|
|
1005
|
+
await asyncio.gather(*in_flight, return_exceptions=True)
|
|
1006
|
+
raise
|
|
1007
|
+
|
|
1008
|
+
elapsed_time = time.perf_counter() - start_time
|
|
1009
|
+
logger.info(
|
|
1010
|
+
"[Consume continuous] Finished. Processed=%d in %.2f seconds",
|
|
1011
|
+
processed,
|
|
1012
|
+
elapsed_time,
|
|
1013
|
+
)
|
|
1014
|
+
return processed
|
|
1015
|
+
|
|
1016
|
+
if policy.loop.mode == "continuous":
|
|
1017
|
+
return await _consume_continuous()
|
|
1018
|
+
|
|
880
1019
|
while True:
|
|
881
1020
|
batch_number += 1
|
|
882
1021
|
|
|
883
1022
|
# ============================================================
|
|
884
1023
|
# FETCH
|
|
885
1024
|
# ============================================================
|
|
886
|
-
logger.
|
|
1025
|
+
logger.debug(f"Fetching transactions batch with fetch policy: {policy.fetch.model_dump_json(indent=2)}")
|
|
887
1026
|
success, result = await self._handle_fetch(conn, policy.fetch)
|
|
888
1027
|
|
|
889
1028
|
if not success:
|
|
@@ -941,7 +1080,7 @@ class AsyncConsumerMixin(ABC):
|
|
|
941
1080
|
else:
|
|
942
1081
|
batch_context = None # Use current context
|
|
943
1082
|
|
|
944
|
-
logger.
|
|
1083
|
+
logger.debug(
|
|
945
1084
|
f"Starting batch processing of "
|
|
946
1085
|
f"{len(transactions)} transaction(s) "
|
|
947
1086
|
f"from fetch handler with "
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Optional, Union
|
|
1
|
+
from typing import Literal, Optional, Union
|
|
2
2
|
|
|
3
3
|
from pydantic import BaseModel, Field, field_validator
|
|
4
4
|
|
|
@@ -161,11 +161,20 @@ class ExceptionPolicy(BaseModel):
|
|
|
161
161
|
|
|
162
162
|
|
|
163
163
|
class ConsumerLoopPolicy(BaseModel):
|
|
164
|
+
mode: Literal["batch", "continuous"] = Field(default="batch")
|
|
164
165
|
concurrency: ConcurrencyPolicy = Field(default_factory=ConcurrencyPolicy)
|
|
165
166
|
timeout: Optional[float] = Field(default=None, ge=0)
|
|
166
167
|
limit: Optional[int] = Field(default=None, ge=0)
|
|
167
168
|
streaming: bool = Field(default=False)
|
|
168
169
|
|
|
170
|
+
@field_validator("mode", mode="before")
|
|
171
|
+
@classmethod
|
|
172
|
+
def _normalize_mode(cls, v):
|
|
173
|
+
v = _normalize_optional(v)
|
|
174
|
+
if v is None:
|
|
175
|
+
return "batch"
|
|
176
|
+
return v.strip().lower() if isinstance(v, str) else v
|
|
177
|
+
|
|
169
178
|
@field_validator("timeout", "limit", mode="before")
|
|
170
179
|
@classmethod
|
|
171
180
|
def _normalize_optional_numbers(cls, v):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/__init__.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/connector.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/excel/__init__.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/excel/connector.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/excel/models.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/excel/service.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/connector.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/models.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/service.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/nylas/utils.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/pipefy/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/pipefy/models.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/pipefy/service.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/pipefy/version.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/postgres/models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/rabbitmq/helper.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/rabbitmq/models.py
RENAMED
|
File without changes
|
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/sqs/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/sqs/connector.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/sqs/models.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/sqs/service.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/connector/transaction.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/mixins/__init__.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/mixins/metrics.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/task/mixins/producer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/telemetry/__init__.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/telemetry/_resource.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/telemetry/logging.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/telemetry/metrics.py
RENAMED
|
File without changes
|
{ergon_framework_python-0.1.8 → ergon_framework_python-0.1.9}/src/ergon/telemetry/tracing.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|