feldera 0.146.0__tar.gz → 0.148.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.

Potentially problematic release.


This version of feldera might be problematic. Click here for more details.

Files changed (30) hide show
  1. {feldera-0.146.0 → feldera-0.148.0}/PKG-INFO +1 -1
  2. {feldera-0.146.0 → feldera-0.148.0}/feldera/enums.py +91 -93
  3. {feldera-0.146.0 → feldera-0.148.0}/feldera/pipeline.py +62 -7
  4. {feldera-0.146.0 → feldera-0.148.0}/feldera/rest/_httprequests.py +5 -0
  5. {feldera-0.146.0 → feldera-0.148.0}/feldera/rest/feldera_client.py +121 -97
  6. {feldera-0.146.0 → feldera-0.148.0}/feldera/rest/pipeline.py +13 -0
  7. {feldera-0.146.0 → feldera-0.148.0}/feldera.egg-info/PKG-INFO +1 -1
  8. {feldera-0.146.0 → feldera-0.148.0}/pyproject.toml +1 -1
  9. {feldera-0.146.0 → feldera-0.148.0}/README.md +0 -0
  10. {feldera-0.146.0 → feldera-0.148.0}/feldera/__init__.py +0 -0
  11. {feldera-0.146.0 → feldera-0.148.0}/feldera/_callback_runner.py +0 -0
  12. {feldera-0.146.0 → feldera-0.148.0}/feldera/_helpers.py +0 -0
  13. {feldera-0.146.0 → feldera-0.148.0}/feldera/output_handler.py +0 -0
  14. {feldera-0.146.0 → feldera-0.148.0}/feldera/pipeline_builder.py +0 -0
  15. {feldera-0.146.0 → feldera-0.148.0}/feldera/rest/__init__.py +0 -0
  16. {feldera-0.146.0 → feldera-0.148.0}/feldera/rest/_helpers.py +0 -0
  17. {feldera-0.146.0 → feldera-0.148.0}/feldera/rest/config.py +0 -0
  18. {feldera-0.146.0 → feldera-0.148.0}/feldera/rest/errors.py +0 -0
  19. {feldera-0.146.0 → feldera-0.148.0}/feldera/rest/feldera_config.py +0 -0
  20. {feldera-0.146.0 → feldera-0.148.0}/feldera/rest/sql_table.py +0 -0
  21. {feldera-0.146.0 → feldera-0.148.0}/feldera/rest/sql_view.py +0 -0
  22. {feldera-0.146.0 → feldera-0.148.0}/feldera/runtime_config.py +0 -0
  23. {feldera-0.146.0 → feldera-0.148.0}/feldera/stats.py +0 -0
  24. {feldera-0.146.0 → feldera-0.148.0}/feldera/tests/test_datafusionize.py +0 -0
  25. {feldera-0.146.0 → feldera-0.148.0}/feldera/testutils.py +0 -0
  26. {feldera-0.146.0 → feldera-0.148.0}/feldera.egg-info/SOURCES.txt +0 -0
  27. {feldera-0.146.0 → feldera-0.148.0}/feldera.egg-info/dependency_links.txt +0 -0
  28. {feldera-0.146.0 → feldera-0.148.0}/feldera.egg-info/requires.txt +0 -0
  29. {feldera-0.146.0 → feldera-0.148.0}/feldera.egg-info/top_level.txt +0 -0
  30. {feldera-0.146.0 → feldera-0.148.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: feldera
3
- Version: 0.146.0
3
+ Version: 0.148.0
4
4
  Summary: The feldera python client
5
5
  Author-email: Feldera Team <dev@feldera.com>
6
6
  License: MIT
@@ -34,131 +34,129 @@ class BuildMode(Enum):
34
34
  GET_OR_CREATE = 3
35
35
 
36
36
 
37
- class PipelineStatus(Enum):
37
+ class DeploymentDesiredStatus(Enum):
38
+ """
39
+ Deployment desired status of the pipeline.
38
40
  """
39
- Represents the state that this pipeline is currently in.
40
41
 
41
- .. code-block:: text
42
+ STOPPED = 0
43
+ UNAVAILABLE = 1
44
+ STANDBY = 2
45
+ PAUSED = 3
46
+ RUNNING = 4
47
+ SUSPENDED = 5
42
48
 
43
- Stopped ◄─────────── Stopping ◄───── All states can transition
44
- │ ▲ to Stopping by either:
45
- /start or /pause │ │ (1) user calling /stop?force=true, or;
46
- ▼ │ (2) pipeline encountering a fatal
47
- ⌛Provisioning Suspending resource or runtime error,
48
- │ ▲ having the system call /stop?force=true
49
- ▼ │ /stop effectively
50
- ⌛Initializing ─────────────┤ ?force=false
51
- │ │
52
- ┌─────────┼────────────────────┴─────┐
53
- │ ▼ │
54
- │ Paused ◄──────► Unavailable │
55
- │ │ ▲ ▲ │
56
- │ /start │ │ /pause │ │
57
- │ ▼ │ │ │
58
- │ Running ◄─────────────┘ │
59
- └────────────────────────────────────┘
49
+ @staticmethod
50
+ def from_str(value):
51
+ for member in DeploymentDesiredStatus:
52
+ if member.name.lower() == value.lower():
53
+ return member
54
+ raise ValueError(
55
+ f"Unknown value '{value}' for enum {DeploymentDesiredStatus.__name__}"
56
+ )
60
57
 
61
- """
62
58
 
63
- NOT_FOUND = 0
59
+ class DeploymentResourcesDesiredStatus(Enum):
64
60
  """
65
- The pipeline has not been created yet.
61
+ The desired status of deployment resources of the pipeline.
66
62
  """
67
63
 
68
- STOPPED = 1
69
- """
70
- The pipeline has not (yet) been started or has been stopped either
71
- manually by the user or automatically by the system due to a
72
- resource or runtime error.
64
+ STOPPED = 0
65
+ PROVISIONED = 1
73
66
 
74
- The pipeline remains in this state until:
67
+ @staticmethod
68
+ def from_str(value):
69
+ for member in DeploymentResourcesDesiredStatus:
70
+ if member.name.lower() == value.lower():
71
+ return member
72
+ raise ValueError(
73
+ f"Unknown value '{value}' for enum {DeploymentResourcesDesiredStatus.__name__}"
74
+ )
75
75
 
76
- 1. The user starts it via `/start` or `/pause`, transitioning to `PROVISIONING`.
77
- 2. Early start fails (e.g., compilation failure), transitioning to `STOPPING`.
78
- """
79
76
 
80
- PROVISIONING = 2
77
+ class DeploymentResourcesStatus(Enum):
81
78
  """
82
- Compute (and optionally storage) resources needed for running the pipeline
83
- are being provisioned.
84
-
85
- The pipeline remains in this state until:
86
-
87
- 1. Resources are provisioned successfully, transitioning to `INITIALIZING`.
88
- 2. Provisioning fails or times out, transitioning to `STOPPING`.
89
- 3. The user cancels the pipeline via `/stop`, transitioning to `STOPPING`.
79
+ The desired status of deployment resources of the pipeline.
90
80
  """
91
81
 
92
- INITIALIZING = 3
93
- """
94
- The pipeline is initializing its internal state and connectors.
82
+ STOPPED = 0
83
+ PROVISIONING = 1
84
+ PROVISIONED = 2
85
+ STOPPING = 3
95
86
 
96
- The pipeline remains in this state until:
87
+ @staticmethod
88
+ def from_str(value):
89
+ for member in DeploymentResourcesStatus:
90
+ if member.name.lower() == value.lower():
91
+ return member
92
+ raise ValueError(
93
+ f"Unknown value '{value}' for enum {DeploymentResourcesStatus.__name__}"
94
+ )
97
95
 
98
- 1. Initialization succeeds, transitioning to `PAUSED`.
99
- 2. Initialization fails or times out, transitioning to `STOPPING`.
100
- 3. The user suspends the pipeline via `/suspend`, transitioning to `SUSPENDING`.
101
- 4. The user stops the pipeline via `/stop`, transitioning to `STOPPING`.
102
- """
103
96
 
104
- PAUSED = 4
97
+ class DeploymentRuntimeDesiredStatus(Enum):
105
98
  """
106
- The pipeline is initialized but data processing is paused.
107
-
108
- The pipeline remains in this state until:
109
-
110
- 1. The user starts it via `/start`, transitioning to `RUNNING`.
111
- 2. A runtime error occurs, transitioning to `STOPPING`.
112
- 3. The user suspends it via `/suspend`, transitioning to `SUSPENDING`.
113
- 4. The user stops it via `/stop`, transitioning to `STOPPING`.
99
+ Deployment runtime desired status of the pipeline.
114
100
  """
115
101
 
116
- RUNNING = 5
117
- """
118
- The pipeline is processing data.
102
+ UNAVAILABLE = 0
103
+ STANDBY = 1
104
+ PAUSED = 2
105
+ RUNNING = 3
106
+ SUSPENDED = 4
119
107
 
120
- The pipeline remains in this state until:
108
+ @staticmethod
109
+ def from_str(value):
110
+ for member in DeploymentRuntimeDesiredStatus:
111
+ if member.name.lower() == value.lower():
112
+ return member
113
+ raise ValueError(
114
+ f"Unknown value '{value}' for enum {DeploymentRuntimeDesiredStatus.__name__}"
115
+ )
121
116
 
122
- 1. The user pauses it via `/pause`, transitioning to `PAUSED`.
123
- 2. A runtime error occurs, transitioning to `STOPPING`.
124
- 3. The user suspends it via `/suspend`, transitioning to `SUSPENDING`.
125
- 4. The user stops it via `/stop`, transitioning to `STOPPING`.
126
- """
127
117
 
128
- UNAVAILABLE = 6
118
+ class DeploymentRuntimeStatus(Enum):
129
119
  """
130
- The pipeline was initialized at least once but is currently unreachable
131
- or not ready.
132
-
133
- The pipeline remains in this state until:
134
-
135
- 1. A successful status check transitions it back to `PAUSED` or `RUNNING`.
136
- 2. A runtime error occurs, transitioning to `STOPPING`.
137
- 3. The user suspends it via `/suspend`, transitioning to `SUSPENDING`.
138
- 4. The user stops it via `/stop`, transitioning to `STOPPING`.
139
-
140
- Note: While in this state, `/start` or `/pause` express desired state but
141
- are only applied once the pipeline becomes reachable.
120
+ Deployment runtime status of the pipeline.
142
121
  """
143
122
 
144
- SUSPENDING = 7
145
- """
146
- The pipeline is being suspended to storage.
123
+ UNAVAILABLE = 0
124
+ STANDBY = 1
125
+ INITIALIZING = 2
126
+ BOOTSTRAPPING = 3
127
+ REPLAYING = 4
128
+ PAUSED = 5
129
+ RUNNING = 6
130
+ SUSPENDED = 7
147
131
 
148
- The pipeline remains in this state until:
132
+ @staticmethod
133
+ def from_str(value):
134
+ for member in DeploymentRuntimeStatus:
135
+ if member.name.lower() == value.lower():
136
+ return member
137
+ raise ValueError(
138
+ f"Unknown value '{value}' for enum {DeploymentRuntimeStatus.__name__}"
139
+ )
149
140
 
150
- 1. Suspension succeeds, transitioning to `STOPPING`.
151
- 2. A runtime error occurs, transitioning to `STOPPING`.
152
- """
153
141
 
154
- STOPPING = 8
142
+ class PipelineStatus(Enum):
155
143
  """
156
- The pipeline's compute resources are being scaled down to zero.
157
-
158
- The pipeline remains in this state until deallocation completes,
159
- transitioning to `STOPPED`.
144
+ Represents the state that this pipeline is currently in.
160
145
  """
161
146
 
147
+ NOT_FOUND = 0
148
+ STOPPED = 1
149
+ PROVISIONING = 2
150
+ UNAVAILABLE = 3
151
+ STANDBY = 4
152
+ INITIALIZING = 5
153
+ BOOTSTRAPPING = 6
154
+ REPLAYING = 7
155
+ PAUSED = 8
156
+ RUNNING = 9
157
+ SUSPENDED = 10
158
+ STOPPING = 11
159
+
162
160
  @staticmethod
163
161
  def from_str(value):
164
162
  for member in PipelineStatus:
@@ -16,8 +16,13 @@ from feldera.enums import (
16
16
  ProgramStatus,
17
17
  CheckpointStatus,
18
18
  TransactionStatus,
19
+ StorageStatus,
20
+ DeploymentDesiredStatus,
21
+ DeploymentResourcesDesiredStatus,
22
+ DeploymentResourcesStatus,
23
+ DeploymentRuntimeDesiredStatus,
24
+ DeploymentRuntimeStatus,
19
25
  )
20
- from feldera.enums import StorageStatus
21
26
  from feldera.rest.pipeline import Pipeline as InnerPipeline
22
27
  from feldera.rest.feldera_client import FelderaClient
23
28
  from feldera._callback_runner import _CallbackRunnerInstruction, CallbackRunner
@@ -393,9 +398,7 @@ method or use `Pipeline.resume()` to resume a paused pipeline."""
393
398
 
394
399
  return
395
400
 
396
- self.client.pause_pipeline(
397
- self.name, "Unable to START the pipeline.\n", wait=wait, timeout_s=timeout_s
398
- )
401
+ self.client.start_pipeline_as_paused(self.name, wait=wait, timeout_s=timeout_s)
399
402
  self.__setup_output_listeners()
400
403
  self.resume(timeout_s=timeout_s)
401
404
 
@@ -505,6 +508,20 @@ metrics"""
505
508
 
506
509
  self.client.activate_pipeline(self.name, wait=wait, timeout_s=timeout_s)
507
510
 
511
+ def start_paused(self, wait: bool = True, timeout_s: Optional[float] = None):
512
+ """
513
+ Starts the pipeline in the paused state.
514
+ """
515
+
516
+ self.client.start_pipeline_as_paused(self.name, wait=wait, timeout_s=timeout_s)
517
+
518
+ def start_standby(self, wait: bool = True, timeout_s: Optional[float] = None):
519
+ """
520
+ Starts the pipeline in the standby state.
521
+ """
522
+
523
+ self.client.start_pipeline_as_standby(self.name, wait=wait, timeout_s=timeout_s)
524
+
508
525
  def pause(self, wait: bool = True, timeout_s: Optional[float] = None):
509
526
  """
510
527
  Pause the pipeline.
@@ -562,7 +579,7 @@ metrics"""
562
579
  pipeline to resume.
563
580
  """
564
581
 
565
- self.client.start_pipeline(self.name, wait=wait, timeout_s=timeout_s)
582
+ self.client.resume_pipeline(self.name, wait=wait, timeout_s=timeout_s)
566
583
 
567
584
  def start_transaction(self) -> int:
568
585
  """
@@ -1116,14 +1133,52 @@ pipeline '{self.name}' to sync checkpoint '{uuid}'"""
1116
1133
  self.refresh()
1117
1134
  return self._inner.deployment_config
1118
1135
 
1119
- def deployment_desired_status(self) -> PipelineStatus:
1136
+ def deployment_desired_status(self) -> DeploymentDesiredStatus:
1120
1137
  """
1121
1138
  Return the desired deployment status of the pipeline.
1122
1139
  This is the next state that the pipeline should transition to.
1123
1140
  """
1124
1141
 
1125
1142
  self.refresh()
1126
- return PipelineStatus.from_str(self._inner.deployment_desired_status)
1143
+ return DeploymentDesiredStatus.from_str(self._inner.deployment_desired_status)
1144
+
1145
+ def deployment_resources_desired_status(self) -> DeploymentResourcesDesiredStatus:
1146
+ """
1147
+ Return the desired status of the the deployment resources.
1148
+ """
1149
+
1150
+ self.refresh()
1151
+ return DeploymentResourcesDesiredStatus.from_str(
1152
+ self._inner.deployment_resources_desired_status
1153
+ )
1154
+
1155
+ def deployment_resources_status(self) -> DeploymentResourcesStatus:
1156
+ """
1157
+ Return the status of the deployment resources.
1158
+ """
1159
+
1160
+ self.refresh()
1161
+ return DeploymentResourcesStatus.from_str(
1162
+ self._inner.deployment_resources_status
1163
+ )
1164
+
1165
+ def deployment_runtime_desired_status(self) -> DeploymentRuntimeDesiredStatus:
1166
+ """
1167
+ Return the deployment runtime desired status.
1168
+ """
1169
+
1170
+ self.refresh()
1171
+ return DeploymentRuntimeDesiredStatus.from_str(
1172
+ self._inner.deployment_runtime_desired_status
1173
+ )
1174
+
1175
+ def deployment_runtime_status(self) -> DeploymentRuntimeStatus:
1176
+ """
1177
+ Return the deployment runtime status.
1178
+ """
1179
+
1180
+ self.refresh()
1181
+ return DeploymentRuntimeStatus.from_str(self._inner.deployment_runtime_status)
1127
1182
 
1128
1183
  def deployment_error(self) -> Mapping[str, Any]:
1129
1184
  """
@@ -206,6 +206,11 @@ class HttpRequests:
206
206
  try:
207
207
  request.raise_for_status()
208
208
 
209
+ if request is None:
210
+ # This shouldn't ever be the case, but we've seen it happen
211
+ return FelderaCommunicationError(
212
+ "Failed to Communicate with Feldera Received None as Response",
213
+ )
209
214
  if stream:
210
215
  return request
211
216
  if request.headers.get("content-type") == "text/plain":
@@ -163,6 +163,46 @@ class FelderaClient:
163
163
  logging.debug("still compiling %s, waiting for 100 more milliseconds", name)
164
164
  time.sleep(0.1)
165
165
 
166
+ def __wait_for_pipeline_state(
167
+ self,
168
+ pipeline_name: str,
169
+ state: str,
170
+ timeout_s: float = 300.0,
171
+ start: bool = True,
172
+ ):
173
+ start_time = time.monotonic()
174
+
175
+ while True:
176
+ if timeout_s is not None:
177
+ elapsed = time.monotonic() - start_time
178
+ if elapsed > timeout_s:
179
+ raise TimeoutError(
180
+ f"Timed out waiting for pipeline {pipeline_name} to"
181
+ f"transition to '{state}' state"
182
+ )
183
+
184
+ resp = self.get_pipeline(pipeline_name)
185
+ status = resp.deployment_status
186
+
187
+ if status.lower() == state.lower():
188
+ break
189
+ elif (
190
+ status == "Stopped"
191
+ and len(resp.deployment_error or {}) > 0
192
+ and resp.deployment_desired_status == "Stopped"
193
+ ):
194
+ err_msg = "Unable to START the pipeline:\n" if start else ""
195
+ raise RuntimeError(
196
+ f"""{err_msg}Unable to transition the pipeline to '{state}'.
197
+ Reason: The pipeline is in a STOPPED state due to the following error:
198
+ {resp.deployment_error.get("message", "")}"""
199
+ )
200
+
201
+ logging.debug(
202
+ "still starting %s, waiting for 100 more milliseconds", pipeline_name
203
+ )
204
+ time.sleep(0.1)
205
+
166
206
  def create_pipeline(self, pipeline: Pipeline) -> Pipeline:
167
207
  """
168
208
  Create a pipeline if it doesn't exist and wait for it to compile
@@ -284,9 +324,10 @@ class FelderaClient:
284
324
  """
285
325
 
286
326
  :param pipeline_name: The name of the pipeline to activate
287
- :param wait: Set True to wait for the pipeline to activate. True by default
288
- :param timeout_s: The amount of time in seconds to wait for the pipeline
289
- to activate. 300 seconds by default.
327
+ :param wait: Set True to wait for the pipeline to activate. True by
328
+ default
329
+ :param timeout_s: The amount of time in seconds to wait for the
330
+ pipeline to activate. 300 seconds by default.
290
331
  """
291
332
 
292
333
  if timeout_s is None:
@@ -299,46 +340,23 @@ class FelderaClient:
299
340
  if not wait:
300
341
  return
301
342
 
302
- start_time = time.monotonic()
343
+ self.__wait_for_pipeline_state(pipeline_name, "running", timeout_s)
303
344
 
304
- while True:
305
- if timeout_s is not None:
306
- elapsed = time.monotonic() - start_time
307
- if elapsed > timeout_s:
308
- raise TimeoutError(
309
- f"Timed out waiting for pipeline {pipeline_name} to activate"
310
- )
311
-
312
- resp = self.get_pipeline(pipeline_name)
313
- status = resp.deployment_status
314
-
315
- if status == "Running":
316
- break
317
- elif (
318
- status == "Stopped"
319
- and len(resp.deployment_error or {}) > 0
320
- and resp.deployment_desired_status == "Stopped"
321
- ):
322
- raise RuntimeError(
323
- f"""Unable to ACTIVATE the pipeline.
324
- Reason: The pipeline is in a STOPPED state due to the following error:
325
- {resp.deployment_error.get("message", "")}"""
326
- )
327
-
328
- logging.debug(
329
- "still starting %s, waiting for 100 more milliseconds", pipeline_name
330
- )
331
- time.sleep(0.1)
332
-
333
- def start_pipeline(
334
- self, pipeline_name: str, wait: bool = True, timeout_s: Optional[float] = 300
345
+ def _inner_start_pipeline(
346
+ self,
347
+ pipeline_name: str,
348
+ initial: str = "running",
349
+ wait: bool = True,
350
+ timeout_s: Optional[float] = 300,
335
351
  ):
336
352
  """
337
353
 
338
354
  :param pipeline_name: The name of the pipeline to start
355
+ :param initial: The initial state to start the pipeline in. "running"
356
+ by default.
339
357
  :param wait: Set True to wait for the pipeline to start. True by default
340
- :param timeout_s: The amount of time in seconds to wait for the pipeline
341
- to start. 300 seconds by default.
358
+ :param timeout_s: The amount of time in seconds to wait for the
359
+ pipeline to start. 300 seconds by default.
342
360
  """
343
361
 
344
362
  if timeout_s is None:
@@ -346,55 +364,64 @@ Reason: The pipeline is in a STOPPED state due to the following error:
346
364
 
347
365
  self.http.post(
348
366
  path=f"/pipelines/{pipeline_name}/start",
367
+ params={"initial": initial},
349
368
  )
350
369
 
351
370
  if not wait:
352
371
  return
353
372
 
354
- start_time = time.monotonic()
373
+ self.__wait_for_pipeline_state(pipeline_name, initial, timeout_s)
355
374
 
356
- while True:
357
- if timeout_s is not None:
358
- elapsed = time.monotonic() - start_time
359
- if elapsed > timeout_s:
360
- raise TimeoutError(
361
- f"Timed out waiting for pipeline {pipeline_name} to start"
362
- )
375
+ def start_pipeline(
376
+ self, pipeline_name: str, wait: bool = True, timeout_s: Optional[float] = 300
377
+ ):
378
+ """
363
379
 
364
- resp = self.get_pipeline(pipeline_name)
365
- status = resp.deployment_status
380
+ :param pipeline_name: The name of the pipeline to start
381
+ :param wait: Set True to wait for the pipeline to start.
382
+ True by default
383
+ :param timeout_s: The amount of time in seconds to wait for the
384
+ pipeline to start. 300 seconds by default.
385
+ """
366
386
 
367
- if status == "Running":
368
- break
369
- elif (
370
- status == "Stopped"
371
- and len(resp.deployment_error or {}) > 0
372
- and resp.deployment_desired_status == "Stopped"
373
- ):
374
- raise RuntimeError(
375
- f"""Unable to START the pipeline.
376
- Reason: The pipeline is in a STOPPED state due to the following error:
377
- {resp.deployment_error.get("message", "")}"""
378
- )
387
+ self._inner_start_pipeline(pipeline_name, "running", wait, timeout_s)
379
388
 
380
- logging.debug(
381
- "still starting %s, waiting for 100 more milliseconds", pipeline_name
382
- )
383
- time.sleep(0.1)
389
+ def start_pipeline_as_paused(
390
+ self, pipeline_name: str, wait: bool = True, timeout_s: Optional[float] = 300
391
+ ):
392
+ """
393
+ :param pipeline_name: The name of the pipeline to start as paused.
394
+ :param wait: Set True to wait for the pipeline to start as pause.
395
+ True by default
396
+ :param timeout_s: The amount of time in seconds to wait for the
397
+ pipeline to start. 300 seconds by default.
398
+ """
384
399
 
385
- def pause_pipeline(
400
+ self._inner_start_pipeline(pipeline_name, "paused", wait, timeout_s)
401
+
402
+ def start_pipeline_as_standby(
403
+ self, pipeline_name: str, wait: bool = True, timeout_s: Optional[float] = 300
404
+ ):
405
+ """
406
+ :param pipeline_name: The name of the pipeline to start as standby.
407
+ :param wait: Set True to wait for the pipeline to start as standby.
408
+ True by default
409
+ :param timeout_s: The amount of time in seconds to wait for the
410
+ pipeline to start. 300 seconds by default.
411
+ """
412
+
413
+ self._inner_start_pipeline(pipeline_name, "paused", wait, timeout_s)
414
+
415
+ def resume_pipeline(
386
416
  self,
387
417
  pipeline_name: str,
388
- error_message: str = None,
389
418
  wait: bool = True,
390
419
  timeout_s: Optional[float] = 300,
391
420
  ):
392
421
  """
393
- Stop a pipeline
422
+ Resume a pipeline
394
423
 
395
424
  :param pipeline_name: The name of the pipeline to stop
396
- :param error_message: The error message to show if the pipeline is in
397
- STOPPED state due to a failure.
398
425
  :param wait: Set True to wait for the pipeline to pause. True by default
399
426
  :param timeout_s: The amount of time in seconds to wait for the pipeline
400
427
  to pause. 300 seconds by default.
@@ -404,45 +431,42 @@ Reason: The pipeline is in a STOPPED state due to the following error:
404
431
  timeout_s = 300
405
432
 
406
433
  self.http.post(
407
- path=f"/pipelines/{pipeline_name}/pause",
434
+ path=f"/pipelines/{pipeline_name}/resume",
408
435
  )
409
436
 
410
437
  if not wait:
411
438
  return
412
439
 
413
- if error_message is None:
414
- error_message = "Unable to PAUSE the pipeline.\n"
440
+ self.__wait_for_pipeline_state(pipeline_name, "running", timeout_s)
415
441
 
416
- start_time = time.monotonic()
442
+ def pause_pipeline(
443
+ self,
444
+ pipeline_name: str,
445
+ wait: bool = True,
446
+ timeout_s: Optional[float] = 300,
447
+ ):
448
+ """
449
+ Pause a pipeline
417
450
 
418
- while True:
419
- if timeout_s is not None:
420
- elapsed = time.monotonic() - start_time
421
- if elapsed > timeout_s:
422
- raise TimeoutError(
423
- f"Timed out waiting for pipeline {pipeline_name} to pause"
424
- )
451
+ :param pipeline_name: The name of the pipeline to stop
452
+ :param error_message: The error message to show if the pipeline is in
453
+ STOPPED state due to a failure.
454
+ :param wait: Set True to wait for the pipeline to pause. True by default
455
+ :param timeout_s: The amount of time in seconds to wait for the pipeline
456
+ to pause. 300 seconds by default.
457
+ """
425
458
 
426
- resp = self.get_pipeline(pipeline_name)
427
- status = resp.deployment_status
459
+ if timeout_s is None:
460
+ timeout_s = 300
428
461
 
429
- if status == "Paused":
430
- break
431
- elif (
432
- status == "Stopped"
433
- and len(resp.deployment_error or {}) > 0
434
- and resp.deployment_desired_status == "Stopped"
435
- ):
436
- raise RuntimeError(
437
- error_message
438
- + f"""Reason: The pipeline is in a STOPPED state due to the following error:
439
- {resp.deployment_error.get("message", "")}"""
440
- )
462
+ self.http.post(
463
+ path=f"/pipelines/{pipeline_name}/pause",
464
+ )
441
465
 
442
- logging.debug(
443
- "still pausing %s, waiting for 100 more milliseconds", pipeline_name
444
- )
445
- time.sleep(0.1)
466
+ if not wait:
467
+ return
468
+
469
+ self.__wait_for_pipeline_state(pipeline_name, "paused", timeout_s)
446
470
 
447
471
  def stop_pipeline(
448
472
  self,
@@ -47,6 +47,9 @@ class Pipeline:
47
47
  self.program_version: Optional[int] = None
48
48
  self.deployment_config: Optional[dict] = None
49
49
  self.deployment_desired_status: Optional[str] = None
50
+ self.deployment_desired_status_since: Optional[str] = None
51
+ self.deployment_id: Optional[str] = None
52
+ self.deployment_initial: Optional[str] = None
50
53
  self.deployment_error: Optional[dict] = None
51
54
  self.deployment_location: Optional[str] = None
52
55
  self.program_info: Optional[dict] = (
@@ -57,6 +60,16 @@ class Pipeline:
57
60
  self.program_error: Optional[dict] = None
58
61
  self.storage_status: Optional[str] = None
59
62
 
63
+ self.deployment_resources_desired_status: Optional[str] = None
64
+ self.deployment_resources_desired_status_since: Optional[str] = None
65
+ self.deployment_resources_status: Optional[str] = None
66
+ self.deployment_resources_status_since: Optional[str] = None
67
+
68
+ self.deployment_runtime_desired_status: Optional[str] = None
69
+ self.deployment_runtime_desired_status_since: Optional[str] = None
70
+ self.deployment_runtime_status: Optional[str] = None
71
+ self.deployment_runtime_status_since: Optional[str] = None
72
+
60
73
  @classmethod
61
74
  def from_dict(cls, d: Mapping[str, Any]):
62
75
  pipeline = cls("", "", "", "", {}, {})
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: feldera
3
- Version: 0.146.0
3
+ Version: 0.148.0
4
4
  Summary: The feldera python client
5
5
  Author-email: Feldera Team <dev@feldera.com>
6
6
  License: MIT
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
  name = "feldera"
7
7
  readme = "README.md"
8
8
  description = "The feldera python client"
9
- version = "0.146.0"
9
+ version = "0.148.0"
10
10
  license = { text = "MIT" }
11
11
  requires-python = ">=3.10"
12
12
  authors = [
File without changes
File without changes
File without changes
File without changes
File without changes