cadence-python-client 0.1.0__py3-none-any.whl
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.
- cadence/__init__.py +18 -0
- cadence/_internal/__init__.py +8 -0
- cadence/_internal/activity/__init__.py +5 -0
- cadence/_internal/activity/_activity_executor.py +113 -0
- cadence/_internal/activity/_context.py +58 -0
- cadence/_internal/rpc/__init__.py +0 -0
- cadence/_internal/rpc/error.py +148 -0
- cadence/_internal/rpc/retry.py +104 -0
- cadence/_internal/rpc/yarpc.py +42 -0
- cadence/_internal/workflow/__init__.py +0 -0
- cadence/_internal/workflow/context.py +121 -0
- cadence/_internal/workflow/decision_events_iterator.py +161 -0
- cadence/_internal/workflow/decisions_helper.py +312 -0
- cadence/_internal/workflow/deterministic_event_loop.py +498 -0
- cadence/_internal/workflow/history_event_iterator.py +58 -0
- cadence/_internal/workflow/statemachine/__init__.py +0 -0
- cadence/_internal/workflow/statemachine/activity_state_machine.py +106 -0
- cadence/_internal/workflow/statemachine/decision_manager.py +157 -0
- cadence/_internal/workflow/statemachine/decision_state_machine.py +87 -0
- cadence/_internal/workflow/statemachine/event_dispatcher.py +76 -0
- cadence/_internal/workflow/statemachine/timer_state_machine.py +73 -0
- cadence/_internal/workflow/workflow_engine.py +245 -0
- cadence/_internal/workflow/workflow_intance.py +44 -0
- cadence/activity.py +255 -0
- cadence/api/v1/__init__.py +92 -0
- cadence/api/v1/common_pb2.py +90 -0
- cadence/api/v1/common_pb2.pyi +200 -0
- cadence/api/v1/common_pb2_grpc.py +24 -0
- cadence/api/v1/decision_pb2.py +67 -0
- cadence/api/v1/decision_pb2.pyi +225 -0
- cadence/api/v1/decision_pb2_grpc.py +24 -0
- cadence/api/v1/domain_pb2.py +68 -0
- cadence/api/v1/domain_pb2.pyi +145 -0
- cadence/api/v1/domain_pb2_grpc.py +24 -0
- cadence/api/v1/error_pb2.py +59 -0
- cadence/api/v1/error_pb2.pyi +82 -0
- cadence/api/v1/error_pb2_grpc.py +24 -0
- cadence/api/v1/history_pb2.py +134 -0
- cadence/api/v1/history_pb2.pyi +780 -0
- cadence/api/v1/history_pb2_grpc.py +24 -0
- cadence/api/v1/query_pb2.py +49 -0
- cadence/api/v1/query_pb2.pyi +59 -0
- cadence/api/v1/query_pb2_grpc.py +24 -0
- cadence/api/v1/service_domain_pb2.py +76 -0
- cadence/api/v1/service_domain_pb2.pyi +164 -0
- cadence/api/v1/service_domain_pb2_grpc.py +327 -0
- cadence/api/v1/service_meta_pb2.py +41 -0
- cadence/api/v1/service_meta_pb2.pyi +17 -0
- cadence/api/v1/service_meta_pb2_grpc.py +97 -0
- cadence/api/v1/service_visibility_pb2.py +71 -0
- cadence/api/v1/service_visibility_pb2.pyi +149 -0
- cadence/api/v1/service_visibility_pb2_grpc.py +362 -0
- cadence/api/v1/service_worker_pb2.py +116 -0
- cadence/api/v1/service_worker_pb2.pyi +350 -0
- cadence/api/v1/service_worker_pb2_grpc.py +743 -0
- cadence/api/v1/service_workflow_pb2.py +126 -0
- cadence/api/v1/service_workflow_pb2.pyi +395 -0
- cadence/api/v1/service_workflow_pb2_grpc.py +861 -0
- cadence/api/v1/tasklist_pb2.py +78 -0
- cadence/api/v1/tasklist_pb2.pyi +147 -0
- cadence/api/v1/tasklist_pb2_grpc.py +24 -0
- cadence/api/v1/visibility_pb2.py +47 -0
- cadence/api/v1/visibility_pb2.pyi +53 -0
- cadence/api/v1/visibility_pb2_grpc.py +24 -0
- cadence/api/v1/workflow_pb2.py +89 -0
- cadence/api/v1/workflow_pb2.pyi +365 -0
- cadence/api/v1/workflow_pb2_grpc.py +24 -0
- cadence/client.py +382 -0
- cadence/data_converter.py +78 -0
- cadence/error.py +111 -0
- cadence/metrics/__init__.py +12 -0
- cadence/metrics/constants.py +136 -0
- cadence/metrics/metrics.py +56 -0
- cadence/metrics/prometheus.py +165 -0
- cadence/sample/__init__.py +1 -0
- cadence/sample/client_example.py +15 -0
- cadence/sample/grpc_usage_example.py +230 -0
- cadence/sample/simple_usage_example.py +155 -0
- cadence/signal.py +174 -0
- cadence/worker/__init__.py +13 -0
- cadence/worker/_activity.py +60 -0
- cadence/worker/_base_task_handler.py +71 -0
- cadence/worker/_decision.py +62 -0
- cadence/worker/_decision_task_handler.py +285 -0
- cadence/worker/_poller.py +64 -0
- cadence/worker/_registry.py +245 -0
- cadence/worker/_types.py +26 -0
- cadence/worker/_worker.py +56 -0
- cadence/workflow.py +271 -0
- cadence_python_client-0.1.0.dist-info/METADATA +180 -0
- cadence_python_client-0.1.0.dist-info/RECORD +95 -0
- cadence_python_client-0.1.0.dist-info/WHEEL +5 -0
- cadence_python_client-0.1.0.dist-info/licenses/LICENSE +201 -0
- cadence_python_client-0.1.0.dist-info/licenses/NOTICE +19 -0
- cadence_python_client-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Metric name constants for Cadence client matching Go client naming convention."""
|
|
2
|
+
|
|
3
|
+
# Metric name prefix
|
|
4
|
+
CADENCE_METRICS_PREFIX = "cadence-"
|
|
5
|
+
|
|
6
|
+
# Workflow Creation metrics
|
|
7
|
+
WORKFLOW_START_COUNTER = CADENCE_METRICS_PREFIX + "workflow-start"
|
|
8
|
+
WORKFLOW_START_ASYNC_COUNTER = CADENCE_METRICS_PREFIX + "workflow-start-async"
|
|
9
|
+
WORKFLOW_COMPLETED_COUNTER = CADENCE_METRICS_PREFIX + "workflow-completed"
|
|
10
|
+
WORKFLOW_CANCELED_COUNTER = CADENCE_METRICS_PREFIX + "workflow-canceled"
|
|
11
|
+
WORKFLOW_FAILED_COUNTER = CADENCE_METRICS_PREFIX + "workflow-failed"
|
|
12
|
+
WORKFLOW_CONTINUE_AS_NEW_COUNTER = CADENCE_METRICS_PREFIX + "workflow-continue-as-new"
|
|
13
|
+
WORKFLOW_END_TO_END_LATENCY = CADENCE_METRICS_PREFIX + "workflow-endtoend-latency"
|
|
14
|
+
WORKFLOW_GET_HISTORY_COUNTER = CADENCE_METRICS_PREFIX + "workflow-get-history-total"
|
|
15
|
+
WORKFLOW_GET_HISTORY_FAILED_COUNTER = (
|
|
16
|
+
CADENCE_METRICS_PREFIX + "workflow-get-history-failed"
|
|
17
|
+
)
|
|
18
|
+
WORKFLOW_GET_HISTORY_SUCCEED_COUNTER = (
|
|
19
|
+
CADENCE_METRICS_PREFIX + "workflow-get-history-succeed"
|
|
20
|
+
)
|
|
21
|
+
WORKFLOW_GET_HISTORY_LATENCY = CADENCE_METRICS_PREFIX + "workflow-get-history-latency"
|
|
22
|
+
WORKFLOW_SIGNAL_WITH_START_COUNTER = (
|
|
23
|
+
CADENCE_METRICS_PREFIX + "workflow-signal-with-start"
|
|
24
|
+
)
|
|
25
|
+
WORKFLOW_SIGNAL_WITH_START_ASYNC_COUNTER = (
|
|
26
|
+
CADENCE_METRICS_PREFIX + "workflow-signal-with-start-async"
|
|
27
|
+
)
|
|
28
|
+
DECISION_TIMEOUT_COUNTER = CADENCE_METRICS_PREFIX + "decision-timeout"
|
|
29
|
+
|
|
30
|
+
# Decision Poll metrics
|
|
31
|
+
DECISION_POLL_COUNTER = CADENCE_METRICS_PREFIX + "decision-poll-total"
|
|
32
|
+
DECISION_POLL_FAILED_COUNTER = CADENCE_METRICS_PREFIX + "decision-poll-failed"
|
|
33
|
+
DECISION_POLL_TRANSIENT_FAILED_COUNTER = (
|
|
34
|
+
CADENCE_METRICS_PREFIX + "decision-poll-transient-failed"
|
|
35
|
+
)
|
|
36
|
+
DECISION_POLL_NO_TASK_COUNTER = CADENCE_METRICS_PREFIX + "decision-poll-no-task"
|
|
37
|
+
DECISION_POLL_SUCCEED_COUNTER = CADENCE_METRICS_PREFIX + "decision-poll-succeed"
|
|
38
|
+
DECISION_POLL_LATENCY = CADENCE_METRICS_PREFIX + "decision-poll-latency"
|
|
39
|
+
DECISION_POLL_INVALID_COUNTER = CADENCE_METRICS_PREFIX + "decision-poll-invalid"
|
|
40
|
+
DECISION_SCHEDULED_TO_START_LATENCY = (
|
|
41
|
+
CADENCE_METRICS_PREFIX + "decision-scheduled-to-start-latency"
|
|
42
|
+
)
|
|
43
|
+
DECISION_EXECUTION_FAILED_COUNTER = CADENCE_METRICS_PREFIX + "decision-execution-failed"
|
|
44
|
+
DECISION_EXECUTION_LATENCY = CADENCE_METRICS_PREFIX + "decision-execution-latency"
|
|
45
|
+
DECISION_RESPONSE_FAILED_COUNTER = CADENCE_METRICS_PREFIX + "decision-response-failed"
|
|
46
|
+
DECISION_RESPONSE_LATENCY = CADENCE_METRICS_PREFIX + "decision-response-latency"
|
|
47
|
+
DECISION_TASK_PANIC_COUNTER = CADENCE_METRICS_PREFIX + "decision-task-panic"
|
|
48
|
+
DECISION_TASK_COMPLETED_COUNTER = CADENCE_METRICS_PREFIX + "decision-task-completed"
|
|
49
|
+
DECISION_TASK_FORCE_COMPLETED_COUNTER = (
|
|
50
|
+
CADENCE_METRICS_PREFIX + "decision-task-force-completed"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Activity Poll metrics
|
|
54
|
+
ACTIVITY_POLL_COUNTER = CADENCE_METRICS_PREFIX + "activity-poll-total"
|
|
55
|
+
ACTIVITY_POLL_FAILED_COUNTER = CADENCE_METRICS_PREFIX + "activity-poll-failed"
|
|
56
|
+
ACTIVITY_POLL_TRANSIENT_FAILED_COUNTER = (
|
|
57
|
+
CADENCE_METRICS_PREFIX + "activity-poll-transient-failed"
|
|
58
|
+
)
|
|
59
|
+
ACTIVITY_POLL_NO_TASK_COUNTER = CADENCE_METRICS_PREFIX + "activity-poll-no-task"
|
|
60
|
+
ACTIVITY_POLL_SUCCEED_COUNTER = CADENCE_METRICS_PREFIX + "activity-poll-succeed"
|
|
61
|
+
ACTIVITY_POLL_LATENCY = CADENCE_METRICS_PREFIX + "activity-poll-latency"
|
|
62
|
+
ACTIVITY_SCHEDULED_TO_START_LATENCY = (
|
|
63
|
+
CADENCE_METRICS_PREFIX + "activity-scheduled-to-start-latency"
|
|
64
|
+
)
|
|
65
|
+
ACTIVITY_EXECUTION_FAILED_COUNTER = CADENCE_METRICS_PREFIX + "activity-execution-failed"
|
|
66
|
+
ACTIVITY_EXECUTION_LATENCY = CADENCE_METRICS_PREFIX + "activity-execution-latency"
|
|
67
|
+
ACTIVITY_RESPONSE_LATENCY = CADENCE_METRICS_PREFIX + "activity-response-latency"
|
|
68
|
+
ACTIVITY_RESPONSE_FAILED_COUNTER = CADENCE_METRICS_PREFIX + "activity-response-failed"
|
|
69
|
+
ACTIVITY_END_TO_END_LATENCY = CADENCE_METRICS_PREFIX + "activity-endtoend-latency"
|
|
70
|
+
ACTIVITY_TASK_PANIC_COUNTER = CADENCE_METRICS_PREFIX + "activity-task-panic"
|
|
71
|
+
ACTIVITY_TASK_COMPLETED_COUNTER = CADENCE_METRICS_PREFIX + "activity-task-completed"
|
|
72
|
+
ACTIVITY_TASK_FAILED_COUNTER = CADENCE_METRICS_PREFIX + "activity-task-failed"
|
|
73
|
+
ACTIVITY_TASK_CANCELED_COUNTER = CADENCE_METRICS_PREFIX + "activity-task-canceled"
|
|
74
|
+
ACTIVITY_TASK_COMPLETED_BY_ID_COUNTER = (
|
|
75
|
+
CADENCE_METRICS_PREFIX + "activity-task-completed-by-id"
|
|
76
|
+
)
|
|
77
|
+
ACTIVITY_TASK_FAILED_BY_ID_COUNTER = (
|
|
78
|
+
CADENCE_METRICS_PREFIX + "activity-task-failed-by-id"
|
|
79
|
+
)
|
|
80
|
+
ACTIVITY_TASK_CANCELED_BY_ID_COUNTER = (
|
|
81
|
+
CADENCE_METRICS_PREFIX + "activity-task-canceled-by-id"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Local Activity metrics
|
|
85
|
+
LOCAL_ACTIVITY_TOTAL_COUNTER = CADENCE_METRICS_PREFIX + "local-activity-total"
|
|
86
|
+
LOCAL_ACTIVITY_TIMEOUT_COUNTER = CADENCE_METRICS_PREFIX + "local-activity-timeout"
|
|
87
|
+
LOCAL_ACTIVITY_CANCELED_COUNTER = CADENCE_METRICS_PREFIX + "local-activity-canceled"
|
|
88
|
+
LOCAL_ACTIVITY_FAILED_COUNTER = CADENCE_METRICS_PREFIX + "local-activity-failed"
|
|
89
|
+
LOCAL_ACTIVITY_PANIC_COUNTER = CADENCE_METRICS_PREFIX + "local-activity-panic"
|
|
90
|
+
LOCAL_ACTIVITY_EXECUTION_LATENCY = (
|
|
91
|
+
CADENCE_METRICS_PREFIX + "local-activity-execution-latency"
|
|
92
|
+
)
|
|
93
|
+
LOCALLY_DISPATCHED_ACTIVITY_POLL_COUNTER = (
|
|
94
|
+
CADENCE_METRICS_PREFIX + "locally-dispatched-activity-poll-total"
|
|
95
|
+
)
|
|
96
|
+
LOCALLY_DISPATCHED_ACTIVITY_POLL_NO_TASK_COUNTER = (
|
|
97
|
+
CADENCE_METRICS_PREFIX + "locally-dispatched-activity-poll-no-task"
|
|
98
|
+
)
|
|
99
|
+
LOCALLY_DISPATCHED_ACTIVITY_POLL_SUCCEED_COUNTER = (
|
|
100
|
+
CADENCE_METRICS_PREFIX + "locally-dispatched-activity-poll-succeed"
|
|
101
|
+
)
|
|
102
|
+
ACTIVITY_LOCAL_DISPATCH_FAILED_COUNTER = (
|
|
103
|
+
CADENCE_METRICS_PREFIX + "activity-local-dispatch-failed"
|
|
104
|
+
)
|
|
105
|
+
ACTIVITY_LOCAL_DISPATCH_SUCCEED_COUNTER = (
|
|
106
|
+
CADENCE_METRICS_PREFIX + "activity-local-dispatch-succeed"
|
|
107
|
+
)
|
|
108
|
+
WORKER_PANIC_COUNTER = CADENCE_METRICS_PREFIX + "worker-panic"
|
|
109
|
+
|
|
110
|
+
# Signal metrics
|
|
111
|
+
UNHANDLED_SIGNALS_COUNTER = CADENCE_METRICS_PREFIX + "unhandled-signals"
|
|
112
|
+
CORRUPTED_SIGNALS_COUNTER = CADENCE_METRICS_PREFIX + "corrupted-signals"
|
|
113
|
+
|
|
114
|
+
# Worker metrics
|
|
115
|
+
WORKER_START_COUNTER = CADENCE_METRICS_PREFIX + "worker-start"
|
|
116
|
+
POLLER_START_COUNTER = CADENCE_METRICS_PREFIX + "poller-start"
|
|
117
|
+
|
|
118
|
+
# Client metrics
|
|
119
|
+
CADENCE_REQUEST = CADENCE_METRICS_PREFIX + "request"
|
|
120
|
+
CADENCE_ERROR = CADENCE_METRICS_PREFIX + "error"
|
|
121
|
+
CADENCE_LATENCY = CADENCE_METRICS_PREFIX + "latency"
|
|
122
|
+
CADENCE_INVALID_REQUEST = CADENCE_METRICS_PREFIX + "invalid-request"
|
|
123
|
+
|
|
124
|
+
# Sticky Cache metrics
|
|
125
|
+
STICKY_CACHE_HIT = CADENCE_METRICS_PREFIX + "sticky-cache-hit"
|
|
126
|
+
STICKY_CACHE_MISS = CADENCE_METRICS_PREFIX + "sticky-cache-miss"
|
|
127
|
+
STICKY_CACHE_EVICT = CADENCE_METRICS_PREFIX + "sticky-cache-evict"
|
|
128
|
+
STICKY_CACHE_STALL = CADENCE_METRICS_PREFIX + "sticky-cache-stall"
|
|
129
|
+
STICKY_CACHE_SIZE = CADENCE_METRICS_PREFIX + "sticky-cache-size"
|
|
130
|
+
|
|
131
|
+
# Replay metrics
|
|
132
|
+
NON_DETERMINISTIC_ERROR = CADENCE_METRICS_PREFIX + "non-deterministic-error"
|
|
133
|
+
REPLAY_SUCCEED_COUNTER = CADENCE_METRICS_PREFIX + "replay-succeed"
|
|
134
|
+
REPLAY_FAILED_COUNTER = CADENCE_METRICS_PREFIX + "replay-failed"
|
|
135
|
+
REPLAY_SKIPPED_COUNTER = CADENCE_METRICS_PREFIX + "replay-skipped"
|
|
136
|
+
REPLAY_LATENCY = CADENCE_METRICS_PREFIX + "replay-latency"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Core metrics collection interface and registry for Cadence client."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Dict, Optional, Protocol
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MetricType(Enum):
|
|
11
|
+
"""Types of metrics that can be collected."""
|
|
12
|
+
|
|
13
|
+
COUNTER = "counter"
|
|
14
|
+
GAUGE = "gauge"
|
|
15
|
+
HISTOGRAM = "histogram"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class MetricsEmitter(Protocol):
|
|
19
|
+
"""Protocol for metrics collection backends."""
|
|
20
|
+
|
|
21
|
+
def counter(
|
|
22
|
+
self, key: str, n: int = 1, tags: Optional[Dict[str, str]] = None
|
|
23
|
+
) -> None:
|
|
24
|
+
"""Send a counter metric."""
|
|
25
|
+
...
|
|
26
|
+
|
|
27
|
+
def gauge(
|
|
28
|
+
self, key: str, value: float, tags: Optional[Dict[str, str]] = None
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Send a gauge metric."""
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
def histogram(
|
|
34
|
+
self, key: str, value: float, tags: Optional[Dict[str, str]] = None
|
|
35
|
+
) -> None:
|
|
36
|
+
"""Send a histogram metric."""
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class NoOpMetricsEmitter:
|
|
41
|
+
"""No-op metrics emitter that discards all metrics."""
|
|
42
|
+
|
|
43
|
+
def counter(
|
|
44
|
+
self, key: str, n: int = 1, tags: Optional[Dict[str, str]] = None
|
|
45
|
+
) -> None:
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
def gauge(
|
|
49
|
+
self, key: str, value: float, tags: Optional[Dict[str, str]] = None
|
|
50
|
+
) -> None:
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
def histogram(
|
|
54
|
+
self, key: str, value: float, tags: Optional[Dict[str, str]] = None
|
|
55
|
+
) -> None:
|
|
56
|
+
pass
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""Prometheus metrics integration for Cadence client."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import Dict, Optional
|
|
6
|
+
|
|
7
|
+
from prometheus_client import ( # type: ignore[import-not-found]
|
|
8
|
+
REGISTRY,
|
|
9
|
+
CollectorRegistry,
|
|
10
|
+
Counter,
|
|
11
|
+
Gauge,
|
|
12
|
+
Histogram,
|
|
13
|
+
generate_latest,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from .metrics import MetricsEmitter
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class PrometheusConfig:
|
|
24
|
+
"""Configuration for Prometheus metrics."""
|
|
25
|
+
|
|
26
|
+
# Default labels to apply to all metrics
|
|
27
|
+
default_labels: Dict[str, str] = field(default_factory=dict)
|
|
28
|
+
|
|
29
|
+
# Custom registry (if None, uses default global registry)
|
|
30
|
+
registry: Optional[CollectorRegistry] = None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class PrometheusMetrics(MetricsEmitter):
|
|
34
|
+
"""Prometheus metrics collector implementation."""
|
|
35
|
+
|
|
36
|
+
def __init__(self, config: Optional[PrometheusConfig] = None):
|
|
37
|
+
self.config = config or PrometheusConfig()
|
|
38
|
+
self.registry = self.config.registry or REGISTRY
|
|
39
|
+
|
|
40
|
+
# Track created metrics to avoid duplicates
|
|
41
|
+
self._counters: Dict[str, Counter] = {}
|
|
42
|
+
self._gauges: Dict[str, Gauge] = {}
|
|
43
|
+
self._histograms: Dict[str, Histogram] = {}
|
|
44
|
+
|
|
45
|
+
def _get_metric_name(self, name: str) -> str:
|
|
46
|
+
"""Get the metric name."""
|
|
47
|
+
return name
|
|
48
|
+
|
|
49
|
+
def _merge_labels(self, labels: Optional[Dict[str, str]]) -> Dict[str, str]:
|
|
50
|
+
"""Merge provided labels with default labels."""
|
|
51
|
+
merged = self.config.default_labels.copy()
|
|
52
|
+
if labels:
|
|
53
|
+
merged.update(labels)
|
|
54
|
+
return merged
|
|
55
|
+
|
|
56
|
+
def _get_or_create_counter(
|
|
57
|
+
self, name: str, labels: Optional[Dict[str, str]]
|
|
58
|
+
) -> Counter:
|
|
59
|
+
"""Get or create a Counter metric."""
|
|
60
|
+
metric_name = self._get_metric_name(name)
|
|
61
|
+
|
|
62
|
+
if metric_name not in self._counters:
|
|
63
|
+
label_names = list(self._merge_labels(labels).keys()) if labels else []
|
|
64
|
+
self._counters[metric_name] = Counter(
|
|
65
|
+
metric_name,
|
|
66
|
+
f"Counter metric for {name}",
|
|
67
|
+
labelnames=label_names,
|
|
68
|
+
registry=self.registry,
|
|
69
|
+
)
|
|
70
|
+
logger.debug(f"Created counter metric: {metric_name}")
|
|
71
|
+
|
|
72
|
+
return self._counters[metric_name]
|
|
73
|
+
|
|
74
|
+
def _get_or_create_gauge(
|
|
75
|
+
self, name: str, labels: Optional[Dict[str, str]]
|
|
76
|
+
) -> Gauge:
|
|
77
|
+
"""Get or create a Gauge metric."""
|
|
78
|
+
metric_name = self._get_metric_name(name)
|
|
79
|
+
|
|
80
|
+
if metric_name not in self._gauges:
|
|
81
|
+
label_names = list(self._merge_labels(labels).keys()) if labels else []
|
|
82
|
+
self._gauges[metric_name] = Gauge(
|
|
83
|
+
metric_name,
|
|
84
|
+
f"Gauge metric for {name}",
|
|
85
|
+
labelnames=label_names,
|
|
86
|
+
registry=self.registry,
|
|
87
|
+
)
|
|
88
|
+
logger.debug(f"Created gauge metric: {metric_name}")
|
|
89
|
+
|
|
90
|
+
return self._gauges[metric_name]
|
|
91
|
+
|
|
92
|
+
def _get_or_create_histogram(
|
|
93
|
+
self, name: str, labels: Optional[Dict[str, str]]
|
|
94
|
+
) -> Histogram:
|
|
95
|
+
"""Get or create a Histogram metric."""
|
|
96
|
+
metric_name = self._get_metric_name(name)
|
|
97
|
+
|
|
98
|
+
if metric_name not in self._histograms:
|
|
99
|
+
label_names = list(self._merge_labels(labels).keys()) if labels else []
|
|
100
|
+
self._histograms[metric_name] = Histogram(
|
|
101
|
+
metric_name,
|
|
102
|
+
f"Histogram metric for {name}",
|
|
103
|
+
labelnames=label_names,
|
|
104
|
+
registry=self.registry,
|
|
105
|
+
)
|
|
106
|
+
logger.debug(f"Created histogram metric: {metric_name}")
|
|
107
|
+
|
|
108
|
+
return self._histograms[metric_name]
|
|
109
|
+
|
|
110
|
+
def counter(
|
|
111
|
+
self, key: str, n: int = 1, tags: Optional[Dict[str, str]] = None
|
|
112
|
+
) -> None:
|
|
113
|
+
"""Send a counter metric."""
|
|
114
|
+
try:
|
|
115
|
+
counter = self._get_or_create_counter(key, tags)
|
|
116
|
+
merged_tags = self._merge_labels(tags)
|
|
117
|
+
|
|
118
|
+
if merged_tags:
|
|
119
|
+
counter.labels(**merged_tags).inc(n)
|
|
120
|
+
else:
|
|
121
|
+
counter.inc(n)
|
|
122
|
+
|
|
123
|
+
except Exception as e:
|
|
124
|
+
logger.error(f"Failed to send counter {key}: {e}")
|
|
125
|
+
|
|
126
|
+
def gauge(
|
|
127
|
+
self, key: str, value: float, tags: Optional[Dict[str, str]] = None
|
|
128
|
+
) -> None:
|
|
129
|
+
"""Send a gauge metric."""
|
|
130
|
+
try:
|
|
131
|
+
gauge = self._get_or_create_gauge(key, tags)
|
|
132
|
+
merged_tags = self._merge_labels(tags)
|
|
133
|
+
|
|
134
|
+
if merged_tags:
|
|
135
|
+
gauge.labels(**merged_tags).set(value)
|
|
136
|
+
else:
|
|
137
|
+
gauge.set(value)
|
|
138
|
+
|
|
139
|
+
except Exception as e:
|
|
140
|
+
logger.error(f"Failed to send gauge {key}: {e}")
|
|
141
|
+
|
|
142
|
+
def histogram(
|
|
143
|
+
self, key: str, value: float, tags: Optional[Dict[str, str]] = None
|
|
144
|
+
) -> None:
|
|
145
|
+
"""Send a histogram metric."""
|
|
146
|
+
try:
|
|
147
|
+
histogram = self._get_or_create_histogram(key, tags)
|
|
148
|
+
merged_tags = self._merge_labels(tags)
|
|
149
|
+
|
|
150
|
+
if merged_tags:
|
|
151
|
+
histogram.labels(**merged_tags).observe(value)
|
|
152
|
+
else:
|
|
153
|
+
histogram.observe(value)
|
|
154
|
+
|
|
155
|
+
except Exception as e:
|
|
156
|
+
logger.error(f"Failed to send histogram {key}: {e}")
|
|
157
|
+
|
|
158
|
+
def get_metrics_text(self) -> str:
|
|
159
|
+
"""Get metrics in Prometheus text format."""
|
|
160
|
+
try:
|
|
161
|
+
metrics_bytes = generate_latest(self.registry)
|
|
162
|
+
return metrics_bytes.decode("utf-8") # type: ignore[no-any-return]
|
|
163
|
+
except Exception as e:
|
|
164
|
+
logger.error(f"Failed to generate metrics text: {e}")
|
|
165
|
+
return ""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Sample directory for cadence protobuf import tests
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from cadence.client import Client
|
|
5
|
+
from cadence.worker import Worker, Registry
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def main():
|
|
9
|
+
async with Client(target="localhost:7833", domain="foo") as client:
|
|
10
|
+
worker = Worker(client, "task_list", Registry())
|
|
11
|
+
await worker.run()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if __name__ == "__main__":
|
|
15
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Example demonstrating how to use the generated gRPC code for Cadence services.
|
|
4
|
+
This example shows how to create a gRPC client and make calls to Cadence workflow services.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import grpc
|
|
8
|
+
from cadence.api.v1 import service_workflow_grpc, service_workflow, common
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def create_grpc_channel(
|
|
12
|
+
server_address: str = "localhost:7833", use_ssl: bool = False
|
|
13
|
+
) -> grpc.Channel:
|
|
14
|
+
"""
|
|
15
|
+
Create a gRPC channel to connect to Cadence server.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
server_address: The address of the Cadence server (host:port)
|
|
19
|
+
use_ssl: Whether to use SSL/TLS for the connection
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
grpc.Channel: The gRPC channel
|
|
23
|
+
"""
|
|
24
|
+
if use_ssl:
|
|
25
|
+
# For SSL connections, you would typically use credentials
|
|
26
|
+
credentials = grpc.ssl_channel_credentials()
|
|
27
|
+
return grpc.secure_channel(server_address, credentials)
|
|
28
|
+
else:
|
|
29
|
+
# For insecure connections (development)
|
|
30
|
+
return grpc.insecure_channel(server_address)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def create_workflow_client(
|
|
34
|
+
channel: grpc.Channel,
|
|
35
|
+
) -> service_workflow_grpc.WorkflowAPIStub:
|
|
36
|
+
"""
|
|
37
|
+
Create a gRPC client for the WorkflowAPI service.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
channel: The gRPC channel
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
WorkflowAPIStub: The gRPC client stub
|
|
44
|
+
"""
|
|
45
|
+
return service_workflow_grpc.WorkflowAPIStub(channel)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def example_start_workflow(
|
|
49
|
+
client: service_workflow_grpc.WorkflowAPIStub, domain: str, workflow_id: str
|
|
50
|
+
):
|
|
51
|
+
"""
|
|
52
|
+
Example of starting a workflow execution using gRPC.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
client: The gRPC client
|
|
56
|
+
domain: The Cadence domain
|
|
57
|
+
workflow_id: The workflow ID
|
|
58
|
+
"""
|
|
59
|
+
# Create the request message
|
|
60
|
+
request = service_workflow.StartWorkflowExecutionRequest()
|
|
61
|
+
request.domain = domain
|
|
62
|
+
request.workflow_id = workflow_id
|
|
63
|
+
request.workflow_type.name = "MyWorkflow"
|
|
64
|
+
request.task_list.name = "my-task-list"
|
|
65
|
+
request.input.data = b"workflow input data" # Serialized workflow input
|
|
66
|
+
request.execution_start_to_close_timeout.seconds = 3600 # 1 hour
|
|
67
|
+
request.task_start_to_close_timeout.seconds = 60 # 1 minute
|
|
68
|
+
request.identity = "python-client"
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
# Make the gRPC call
|
|
72
|
+
response = client.StartWorkflowExecution(request)
|
|
73
|
+
print(f"✓ Workflow started successfully: {response}")
|
|
74
|
+
return response
|
|
75
|
+
except grpc.RpcError as e:
|
|
76
|
+
print(f"✗ Failed to start workflow: {e}")
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def example_describe_workflow(
|
|
81
|
+
client: service_workflow_grpc.WorkflowAPIStub,
|
|
82
|
+
domain: str,
|
|
83
|
+
workflow_id: str,
|
|
84
|
+
run_id: str,
|
|
85
|
+
):
|
|
86
|
+
"""
|
|
87
|
+
Example of describing a workflow execution using gRPC.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
client: The gRPC client
|
|
91
|
+
domain: The Cadence domain
|
|
92
|
+
workflow_id: The workflow ID
|
|
93
|
+
run_id: The workflow run ID
|
|
94
|
+
"""
|
|
95
|
+
# Create the request message
|
|
96
|
+
request = service_workflow.DescribeWorkflowExecutionRequest()
|
|
97
|
+
request.domain = domain
|
|
98
|
+
execution = common.WorkflowExecution()
|
|
99
|
+
execution.workflow_id = workflow_id
|
|
100
|
+
execution.run_id = run_id
|
|
101
|
+
request.workflow_execution.CopyFrom(execution)
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
# Make the gRPC call
|
|
105
|
+
response = client.DescribeWorkflowExecution(request)
|
|
106
|
+
print(f"✓ Workflow description: {response}")
|
|
107
|
+
return response
|
|
108
|
+
except grpc.RpcError as e:
|
|
109
|
+
print(f"✗ Failed to describe workflow: {e}")
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def example_get_workflow_history(
|
|
114
|
+
client: service_workflow_grpc.WorkflowAPIStub,
|
|
115
|
+
domain: str,
|
|
116
|
+
workflow_id: str,
|
|
117
|
+
run_id: str,
|
|
118
|
+
):
|
|
119
|
+
"""
|
|
120
|
+
Example of getting workflow execution history using gRPC.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
client: The gRPC client
|
|
124
|
+
domain: The Cadence domain
|
|
125
|
+
workflow_id: The workflow ID
|
|
126
|
+
run_id: The workflow run ID
|
|
127
|
+
"""
|
|
128
|
+
# Create the request message
|
|
129
|
+
request = service_workflow.GetWorkflowExecutionHistoryRequest()
|
|
130
|
+
request.domain = domain
|
|
131
|
+
execution = common.WorkflowExecution()
|
|
132
|
+
execution.workflow_id = workflow_id
|
|
133
|
+
execution.run_id = run_id
|
|
134
|
+
request.workflow_execution.CopyFrom(execution)
|
|
135
|
+
request.page_size = 100
|
|
136
|
+
|
|
137
|
+
try:
|
|
138
|
+
# Make the gRPC call
|
|
139
|
+
response = client.GetWorkflowExecutionHistory(request)
|
|
140
|
+
print(f"✓ Workflow history retrieved: {len(response.history.events)} events")
|
|
141
|
+
return response
|
|
142
|
+
except grpc.RpcError as e:
|
|
143
|
+
print(f"✗ Failed to get workflow history: {e}")
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def example_query_workflow(
|
|
148
|
+
client: service_workflow_grpc.WorkflowAPIStub,
|
|
149
|
+
domain: str,
|
|
150
|
+
workflow_id: str,
|
|
151
|
+
run_id: str,
|
|
152
|
+
query_type: str,
|
|
153
|
+
):
|
|
154
|
+
"""
|
|
155
|
+
Example of querying a workflow using gRPC.
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
client: The gRPC client
|
|
159
|
+
domain: The Cadence domain
|
|
160
|
+
workflow_id: The workflow ID
|
|
161
|
+
run_id: The workflow run ID
|
|
162
|
+
query_type: The type of query to execute
|
|
163
|
+
"""
|
|
164
|
+
# Create the request message
|
|
165
|
+
request = service_workflow.QueryWorkflowRequest()
|
|
166
|
+
request.domain = domain
|
|
167
|
+
execution = common.WorkflowExecution()
|
|
168
|
+
execution.workflow_id = workflow_id
|
|
169
|
+
execution.run_id = run_id
|
|
170
|
+
request.workflow_execution.CopyFrom(execution)
|
|
171
|
+
request.query.query_type = query_type
|
|
172
|
+
request.query.query_args.data = b"query arguments" # Serialized query arguments
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
# Make the gRPC call
|
|
176
|
+
response = client.QueryWorkflow(request)
|
|
177
|
+
print(f"✓ Workflow query result: {response}")
|
|
178
|
+
return response
|
|
179
|
+
except grpc.RpcError as e:
|
|
180
|
+
print(f"✗ Failed to query workflow: {e}")
|
|
181
|
+
return None
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def main():
|
|
185
|
+
"""Main example function."""
|
|
186
|
+
print("Cadence gRPC Client Example")
|
|
187
|
+
print("=" * 40)
|
|
188
|
+
|
|
189
|
+
# Configuration
|
|
190
|
+
server_address = "localhost:7833" # Default Cadence gRPC port
|
|
191
|
+
domain = "test-domain"
|
|
192
|
+
workflow_id = "example-workflow-123"
|
|
193
|
+
run_id = "example-run-456"
|
|
194
|
+
|
|
195
|
+
try:
|
|
196
|
+
# Create gRPC channel
|
|
197
|
+
print(f"Connecting to Cadence server at {server_address}...")
|
|
198
|
+
channel = create_grpc_channel(server_address)
|
|
199
|
+
|
|
200
|
+
# Create gRPC client
|
|
201
|
+
client = create_workflow_client(channel)
|
|
202
|
+
print("✓ gRPC client created successfully")
|
|
203
|
+
|
|
204
|
+
# Example 1: Start a workflow
|
|
205
|
+
print("\n1. Starting a workflow...")
|
|
206
|
+
example_start_workflow(client, domain, workflow_id)
|
|
207
|
+
|
|
208
|
+
# Example 2: Describe a workflow
|
|
209
|
+
print("\n2. Describing a workflow...")
|
|
210
|
+
example_describe_workflow(client, domain, workflow_id, run_id)
|
|
211
|
+
|
|
212
|
+
# Example 3: Get workflow history
|
|
213
|
+
print("\n3. Getting workflow history...")
|
|
214
|
+
example_get_workflow_history(client, domain, workflow_id, run_id)
|
|
215
|
+
|
|
216
|
+
# Example 4: Query a workflow
|
|
217
|
+
print("\n4. Querying a workflow...")
|
|
218
|
+
example_query_workflow(client, domain, workflow_id, run_id, "status")
|
|
219
|
+
|
|
220
|
+
except Exception as e:
|
|
221
|
+
print(f"✗ Error: {e}")
|
|
222
|
+
finally:
|
|
223
|
+
# Close the channel
|
|
224
|
+
if "channel" in locals():
|
|
225
|
+
channel.close()
|
|
226
|
+
print("\n✓ gRPC channel closed")
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
if __name__ == "__main__":
|
|
230
|
+
main()
|