aws-python-helper 1.7.1__tar.gz → 1.8.0__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.
Files changed (60) hide show
  1. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/PKG-INFO +1 -1
  2. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/__init__.py +5 -0
  3. aws_python_helper-1.8.0/aws_python_helper/monitoring/__init__.py +3 -0
  4. aws_python_helper-1.8.0/aws_python_helper/monitoring/run.py +147 -0
  5. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper.egg-info/PKG-INFO +1 -1
  6. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper.egg-info/SOURCES.txt +2 -0
  7. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/pyproject.toml +1 -1
  8. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/README.md +0 -0
  9. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/api/__init__.py +0 -0
  10. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/api/auth_middleware.py +0 -0
  11. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/api/auth_validators.py +0 -0
  12. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/api/base.py +0 -0
  13. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/api/dispatcher.py +0 -0
  14. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/api/exceptions.py +0 -0
  15. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/api/fetcher.py +0 -0
  16. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/api/handler.py +0 -0
  17. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/context/__init__.py +0 -0
  18. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/context/session.py +0 -0
  19. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/context/state_validator.py +0 -0
  20. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/database/__init__.py +0 -0
  21. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/database/database_proxy.py +0 -0
  22. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/database/external_database_proxy.py +0 -0
  23. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/database/external_mongo_manager.py +0 -0
  24. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/database/mongo_manager.py +0 -0
  25. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/fargate/__init__.py +0 -0
  26. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/fargate/executor.py +0 -0
  27. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/fargate/fetcher.py +0 -0
  28. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/fargate/handler.py +0 -0
  29. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/fargate/task_base.py +0 -0
  30. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/invoker/__init__.py +0 -0
  31. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/invoker/api_client.py +0 -0
  32. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/invoker/exceptions.py +0 -0
  33. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/invoker/lambda_invoker.py +0 -0
  34. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/lambda_standalone/__init__.py +0 -0
  35. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/lambda_standalone/base.py +0 -0
  36. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/lambda_standalone/fetcher.py +0 -0
  37. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/lambda_standalone/handler.py +0 -0
  38. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/model_index_sync/__init__.py +0 -0
  39. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/model_index_sync/base.py +0 -0
  40. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/model_query/__init__.py +0 -0
  41. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/model_query/base.py +0 -0
  42. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/permissions/__init__.py +0 -0
  43. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/permissions/catalog.py +0 -0
  44. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/repository/__init__.py +0 -0
  45. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/repository/audit.py +0 -0
  46. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/repository/base.py +0 -0
  47. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/sns/__init__.py +0 -0
  48. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/sns/publisher.py +0 -0
  49. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/sqs/__init__.py +0 -0
  50. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/sqs/consumer_base.py +0 -0
  51. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/sqs/fetcher.py +0 -0
  52. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/sqs/handler.py +0 -0
  53. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/utils/__init__.py +0 -0
  54. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/utils/json_encoder.py +0 -0
  55. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/utils/response.py +0 -0
  56. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper/utils/serializer.py +0 -0
  57. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper.egg-info/dependency_links.txt +0 -0
  58. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper.egg-info/requires.txt +0 -0
  59. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/aws_python_helper.egg-info/top_level.txt +0 -0
  60. {aws_python_helper-1.7.1 → aws_python_helper-1.8.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aws-python-helper
3
- Version: 1.7.1
3
+ Version: 1.8.0
4
4
  Summary: AWS Python Helper Framework
5
5
  Author-email: Fabian Claros <neufabiae@gmail.com>
6
6
  License-Expression: MIT
@@ -57,8 +57,13 @@ from .invoker import (
57
57
  )
58
58
 
59
59
 
60
+ from .monitoring import process_run, RunReporter, ProcessRunPublisher
61
+
60
62
  __all__ = [
61
63
  'API',
64
+ 'process_run',
65
+ 'RunReporter',
66
+ 'ProcessRunPublisher',
62
67
  'SQSConsumer',
63
68
  'MongoManager',
64
69
  'DatabaseProxy',
@@ -0,0 +1,3 @@
1
+ from .run import ProcessRunPublisher, RunReporter, process_run
2
+
3
+ __all__ = ['process_run', 'RunReporter', 'ProcessRunPublisher']
@@ -0,0 +1,147 @@
1
+ """Reporting that a process started and finished, in one line.
2
+
3
+ Two hand-written publishes would work, and the second one would get forgotten on
4
+ the path that matters: the failure. So the boundary is a context manager — enter
5
+ and it says it started, leave and it says how it went, exception included.
6
+
7
+ Nothing here can raise into the caller. Monitoring must never be able to break
8
+ the thing it monitors: a topic that does not exist, credentials that are wrong,
9
+ SNS being slow are all reasons to lose a record, never reasons to fail a run that
10
+ otherwise worked.
11
+ """
12
+
13
+ import logging
14
+ import os
15
+ import uuid
16
+ from contextlib import asynccontextmanager
17
+ from datetime import datetime, timezone
18
+ from typing import Any, Dict, Optional
19
+
20
+ from ..sns.publisher import SNSPublisher
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+ LAUNCHED = "launched"
25
+ RUNNING = "running"
26
+ SUCCESS = "success"
27
+ FAILED = "failed"
28
+
29
+ TOPIC_ENV = "PROCESS_RUNS_TOPIC_ARN"
30
+
31
+
32
+ class ProcessRunPublisher(SNSPublisher):
33
+ pass
34
+
35
+
36
+ class RunReporter:
37
+ """Lo que el proceso usa adentro del bloque para contar cómo le fue."""
38
+
39
+ __slots__ = ("run_id", "process_code", "counters", "scope", "_error")
40
+
41
+ def __init__(self, run_id: str, process_code: str):
42
+ self.run_id = run_id
43
+ self.process_code = process_code
44
+ self.counters: Dict[str, Any] = {}
45
+ self.scope: Optional[str] = None
46
+ self._error: Optional[str] = None
47
+
48
+ def count(self, name: str, amount: int = 1) -> None:
49
+ """Suma a un contador. Lo que se mida con esto se define en el proceso."""
50
+ self.counters[name] = self.counters.get(name, 0) + amount
51
+
52
+
53
+ async def _publish(payload: Dict[str, Any]) -> None:
54
+ """Manda el evento, y si no se puede lo deja en el log y sigue.
55
+
56
+ Se espera a que salga en lugar de dispararlo y seguir: una lambda se congela
57
+ apenas devuelve, y una tarea suelta que todavía no corrió se pierde entera.
58
+ Son milisegundos contra perder el registro.
59
+ """
60
+ topic = os.getenv(TOPIC_ENV, "")
61
+ if not topic:
62
+ logger.warning(
63
+ "%s is not set, so run %s of %s was not reported",
64
+ TOPIC_ENV, payload.get("run_id"), payload.get("process_code"),
65
+ )
66
+ return
67
+
68
+ try:
69
+ await ProcessRunPublisher(topic).publish({"content": _clean(payload)})
70
+ except Exception as error:
71
+ # A propósito no se vuelve a lanzar: perder el registro de una ejecución
72
+ # es malo, tumbar la ejecución por no poder registrarla es peor.
73
+ logger.error("Could not report run %s: %s", payload.get("run_id"), error)
74
+
75
+
76
+ def _clean(payload: Dict[str, Any]) -> Dict[str, Any]:
77
+ return {key: value for key, value in payload.items() if value is not None}
78
+
79
+
80
+ def _now() -> str:
81
+ return datetime.now(timezone.utc).isoformat()
82
+
83
+
84
+ @asynccontextmanager
85
+ async def process_run(
86
+ process_code: str,
87
+ *,
88
+ run_id: Optional[str] = None,
89
+ scope: Optional[str] = None,
90
+ resource_arn: Optional[str] = None,
91
+ request_id: Optional[str] = None,
92
+ ):
93
+ """Reporta el principio y el final de una ejecución.
94
+
95
+ Usage:
96
+ async with process_run("business-region-sync-ct") as run:
97
+ run.count("regions_received")
98
+
99
+ El proceso tiene que estar registrado en core; si no lo está, el evento se
100
+ descarta allá y queda en su log. Eso es a propósito: lo que nadie declaró no
101
+ se está vigilando, y registrarlo solo llenaría la pantalla de ejecuciones que
102
+ nadie puede configurar.
103
+ """
104
+ reporter = RunReporter(run_id or str(uuid.uuid4()), process_code)
105
+ started_at = _now()
106
+
107
+ await _publish({
108
+ "run_id": reporter.run_id,
109
+ "process_code": process_code,
110
+ "status": LAUNCHED,
111
+ "started_at": started_at,
112
+ "scope": scope,
113
+ # Lo único que AWS deja en el ambiente. El ARN completo y el id de la
114
+ # invocación viven en el `context` del handler, que acá no se tiene: quien
115
+ # lo tenga los pasa por `resource_arn` y `request_id`.
116
+ "resource_arn": resource_arn or os.getenv("AWS_LAMBDA_FUNCTION_NAME") or None,
117
+ "request_id": request_id,
118
+ })
119
+
120
+ try:
121
+ yield reporter
122
+ except Exception as error:
123
+ await _publish({
124
+ "run_id": reporter.run_id,
125
+ "process_code": process_code,
126
+ "status": FAILED,
127
+ "started_at": started_at,
128
+ "finished_at": _now(),
129
+ "error": f"{type(error).__name__}: {error}"[:2000],
130
+ "counters": reporter.counters,
131
+ "scope": reporter.scope or scope,
132
+ "request_id": request_id,
133
+ })
134
+ # La excepción sigue su camino: el monitoreo anota lo que pasó, no lo
135
+ # decide. Tragarla acá convertiría una falla en un éxito silencioso.
136
+ raise
137
+ else:
138
+ await _publish({
139
+ "run_id": reporter.run_id,
140
+ "process_code": process_code,
141
+ "status": SUCCESS,
142
+ "started_at": started_at,
143
+ "finished_at": _now(),
144
+ "counters": reporter.counters,
145
+ "scope": reporter.scope or scope,
146
+ "request_id": request_id,
147
+ })
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aws-python-helper
3
- Version: 1.7.1
3
+ Version: 1.8.0
4
4
  Summary: AWS Python Helper Framework
5
5
  Author-email: Fabian Claros <neufabiae@gmail.com>
6
6
  License-Expression: MIT
@@ -39,6 +39,8 @@ aws_python_helper/model_index_sync/__init__.py
39
39
  aws_python_helper/model_index_sync/base.py
40
40
  aws_python_helper/model_query/__init__.py
41
41
  aws_python_helper/model_query/base.py
42
+ aws_python_helper/monitoring/__init__.py
43
+ aws_python_helper/monitoring/run.py
42
44
  aws_python_helper/permissions/__init__.py
43
45
  aws_python_helper/permissions/catalog.py
44
46
  aws_python_helper/repository/__init__.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "aws-python-helper"
7
- version = "1.7.1"
7
+ version = "1.8.0"
8
8
  description = "AWS Python Helper Framework"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"