modal 1.1.3.dev2__tar.gz → 1.1.3.dev4__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.
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/PKG-INFO +1 -1
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_functions.py +47 -25
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/client.pyi +2 -2
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/functions.pyi +6 -6
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/parallel_map.py +21 -2
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/parallel_map.pyi +3 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/api.proto +2 -2
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/api_pb2.pyi +2 -4
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_version/__init__.py +1 -1
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/LICENSE +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/README.md +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/__init__.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/__main__.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_clustered_functions.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_clustered_functions.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_container_entrypoint.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_ipython.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_location.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_object.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_output.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_partial_function.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_pty.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_resolver.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_resources.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_runtime/__init__.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_runtime/asgi.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_runtime/execution_context.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_runtime/telemetry.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_serialization.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_traceback.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_tunnel.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_tunnel.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_type_manager.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/__init__.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/app_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/async_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/blob_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/deprecation.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/docker_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/function_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/git_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/hash_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/http_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/logger.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/mount_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/name_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/package_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/shell_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_utils/time_utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_vendor/__init__.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_vendor/tblib.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/_watcher.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/app.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/app.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/builder/2023.12.312.txt +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/builder/2023.12.txt +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/builder/2024.04.txt +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/builder/2024.10.txt +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/builder/2025.06.txt +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/builder/PREVIEW.txt +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/builder/README.md +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/builder/base-images.json +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/call_graph.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/__init__.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/_download.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/_traceback.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/app.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/cluster.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/config.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/container.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/dict.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/entry_point.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/environment.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/import_refs.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/launch.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/network_file_system.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/profile.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/programs/__init__.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/programs/launch_instance_ssh.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/programs/run_marimo.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/programs/vscode.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/queues.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/run.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/secret.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/token.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/utils.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cli/volume.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/client.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cls.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/cls.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/config.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/container_process.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/container_process.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/dict.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/dict.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/environments.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/environments.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/exception.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/experimental/__init__.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/experimental/flash.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/experimental/flash.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/experimental/ipython.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/file_io.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/file_io.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/file_pattern_matcher.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/functions.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/gpu.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/image.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/image.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/io_streams.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/io_streams.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/mount.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/mount.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/network_file_system.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/network_file_system.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/object.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/object.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/output.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/partial_function.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/partial_function.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/proxy.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/proxy.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/py.typed +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/queue.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/queue.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/retries.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/runner.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/runner.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/running_app.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/sandbox.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/sandbox.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/schedule.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/scheduler_placement.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/secret.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/secret.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/serving.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/serving.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/snapshot.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/snapshot.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/stream_type.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/token_flow.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/token_flow.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/volume.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal/volume.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal.egg-info/requires.txt +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal.egg-info/top_level.txt +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_docs/__init__.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/__init__.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/api_grpc.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/api_pb2.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/modal_options_grpc.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/options.proto +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/options_grpc.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/options_pb2.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/options_pb2.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/options_pb2_grpc.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/options_pb2_grpc.pyi +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_proto/py.typed +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/modal_version/__main__.py +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/pyproject.toml +0 -0
- {modal-1.1.3.dev2 → modal-1.1.3.dev4}/setup.cfg +0 -0
@@ -100,6 +100,10 @@ if TYPE_CHECKING:
|
|
100
100
|
import modal.partial_function
|
101
101
|
|
102
102
|
MAX_INTERNAL_FAILURE_COUNT = 8
|
103
|
+
TERMINAL_STATUSES = (
|
104
|
+
api_pb2.GenericResult.GENERIC_STATUS_SUCCESS,
|
105
|
+
api_pb2.GenericResult.GENERIC_STATUS_TERMINATED,
|
106
|
+
)
|
103
107
|
|
104
108
|
|
105
109
|
@dataclasses.dataclass
|
@@ -300,11 +304,7 @@ class _Invocation:
|
|
300
304
|
|
301
305
|
while True:
|
302
306
|
item = await self._get_single_output(ctx.input_jwt)
|
303
|
-
if item.result.status in
|
304
|
-
api_pb2.GenericResult.GENERIC_STATUS_SUCCESS,
|
305
|
-
api_pb2.GenericResult.GENERIC_STATUS_TERMINATED,
|
306
|
-
):
|
307
|
-
# success or cancellations are "final" results
|
307
|
+
if item.result.status in TERMINAL_STATUSES:
|
308
308
|
return await _process_result(item.result, item.data_format, self.stub, self.client)
|
309
309
|
|
310
310
|
if item.result.status != api_pb2.GenericResult.GENERIC_STATUS_INTERNAL_FAILURE:
|
@@ -411,6 +411,7 @@ class _InputPlaneInvocation:
|
|
411
411
|
client: _Client,
|
412
412
|
input_item: api_pb2.FunctionPutInputsItem,
|
413
413
|
function_id: str,
|
414
|
+
retry_policy: api_pb2.FunctionRetryPolicy,
|
414
415
|
input_plane_region: str,
|
415
416
|
):
|
416
417
|
self.stub = stub
|
@@ -418,6 +419,7 @@ class _InputPlaneInvocation:
|
|
418
419
|
self.attempt_token = attempt_token
|
419
420
|
self.input_item = input_item
|
420
421
|
self.function_id = function_id
|
422
|
+
self.retry_policy = retry_policy
|
421
423
|
self.input_plane_region = input_plane_region
|
422
424
|
|
423
425
|
@staticmethod
|
@@ -453,11 +455,15 @@ class _InputPlaneInvocation:
|
|
453
455
|
response = await retry_transient_errors(stub.AttemptStart, request, metadata=metadata)
|
454
456
|
attempt_token = response.attempt_token
|
455
457
|
|
456
|
-
return _InputPlaneInvocation(
|
458
|
+
return _InputPlaneInvocation(
|
459
|
+
stub, attempt_token, client, input_item, function_id, response.retry_policy, input_plane_region
|
460
|
+
)
|
457
461
|
|
458
462
|
async def run_function(self) -> Any:
|
463
|
+
# User errors including timeouts are managed by the user-specified retry policy.
|
464
|
+
user_retry_manager = RetryManager(self.retry_policy)
|
465
|
+
|
459
466
|
# This will retry when the server returns GENERIC_STATUS_INTERNAL_FAILURE, i.e. lost inputs or worker preemption
|
460
|
-
# TODO(ryan): add logic to retry for user defined retry policy
|
461
467
|
internal_failure_count = 0
|
462
468
|
while True:
|
463
469
|
await_request = api_pb2.AttemptAwaitRequest(
|
@@ -474,32 +480,48 @@ class _InputPlaneInvocation:
|
|
474
480
|
)
|
475
481
|
|
476
482
|
if await_response.HasField("output"):
|
483
|
+
if await_response.output.result.status in TERMINAL_STATUSES:
|
484
|
+
return await _process_result(
|
485
|
+
await_response.output.result, await_response.output.data_format, self.client.stub, self.client
|
486
|
+
)
|
487
|
+
|
477
488
|
if await_response.output.result.status == api_pb2.GenericResult.GENERIC_STATUS_INTERNAL_FAILURE:
|
478
489
|
internal_failure_count += 1
|
479
490
|
# Limit the number of times we retry
|
480
491
|
if internal_failure_count < MAX_INTERNAL_FAILURE_COUNT:
|
481
492
|
# For system failures on the server, we retry immediately,
|
482
493
|
# and the failure does not count towards the retry policy.
|
483
|
-
|
484
|
-
function_id=self.function_id,
|
485
|
-
parent_input_id=current_input_id() or "",
|
486
|
-
input=self.input_item,
|
487
|
-
attempt_token=self.attempt_token,
|
488
|
-
)
|
489
|
-
# TODO(ryan): Add exponential backoff?
|
490
|
-
retry_response = await retry_transient_errors(
|
491
|
-
self.stub.AttemptRetry,
|
492
|
-
retry_request,
|
493
|
-
metadata=metadata,
|
494
|
-
)
|
495
|
-
self.attempt_token = retry_response.attempt_token
|
494
|
+
self.attempt_token = await self._retry_input(metadata)
|
496
495
|
continue
|
497
496
|
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
497
|
+
# We add delays between retries for non-internal failures.
|
498
|
+
delay_ms = user_retry_manager.get_delay_ms()
|
499
|
+
if delay_ms is None:
|
500
|
+
# No more retries either because we reached the retry limit or user didn't set a retry policy
|
501
|
+
# and the limit defaulted to 0.
|
502
|
+
# An unsuccessful status should raise an error when it's converted to an exception.
|
503
|
+
# Note: Blob download is done on the control plane stub not the input plane stub!
|
504
|
+
return await _process_result(
|
505
|
+
await_response.output.result, await_response.output.data_format, self.client.stub, self.client
|
506
|
+
)
|
507
|
+
await asyncio.sleep(delay_ms / 1000)
|
508
|
+
|
509
|
+
await self._retry_input(metadata)
|
510
|
+
|
511
|
+
async def _retry_input(self, metadata: list[tuple[str, str]]) -> str:
|
512
|
+
retry_request = api_pb2.AttemptRetryRequest(
|
513
|
+
function_id=self.function_id,
|
514
|
+
parent_input_id=current_input_id() or "",
|
515
|
+
input=self.input_item,
|
516
|
+
attempt_token=self.attempt_token,
|
517
|
+
)
|
518
|
+
# TODO(ryan): Add exponential backoff?
|
519
|
+
retry_response = await retry_transient_errors(
|
520
|
+
self.stub.AttemptRetry,
|
521
|
+
retry_request,
|
522
|
+
metadata=metadata,
|
523
|
+
)
|
524
|
+
return retry_response.attempt_token
|
503
525
|
|
504
526
|
async def run_generator(self):
|
505
527
|
items_received = 0
|
@@ -33,7 +33,7 @@ class _Client:
|
|
33
33
|
server_url: str,
|
34
34
|
client_type: int,
|
35
35
|
credentials: typing.Optional[tuple[str, str]],
|
36
|
-
version: str = "1.1.3.
|
36
|
+
version: str = "1.1.3.dev4",
|
37
37
|
):
|
38
38
|
"""mdmd:hidden
|
39
39
|
The Modal client object is not intended to be instantiated directly by users.
|
@@ -164,7 +164,7 @@ class Client:
|
|
164
164
|
server_url: str,
|
165
165
|
client_type: int,
|
166
166
|
credentials: typing.Optional[tuple[str, str]],
|
167
|
-
version: str = "1.1.3.
|
167
|
+
version: str = "1.1.3.dev4",
|
168
168
|
):
|
169
169
|
"""mdmd:hidden
|
170
170
|
The Modal client object is not intended to be instantiated directly by users.
|
@@ -433,7 +433,7 @@ class Function(
|
|
433
433
|
|
434
434
|
_call_generator: ___call_generator_spec[typing_extensions.Self]
|
435
435
|
|
436
|
-
class __remote_spec(typing_extensions.Protocol[
|
436
|
+
class __remote_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
437
437
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> ReturnType_INNER:
|
438
438
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
439
439
|
...
|
@@ -442,7 +442,7 @@ class Function(
|
|
442
442
|
"""Calls the function remotely, executing it with the given arguments and returning the execution's result."""
|
443
443
|
...
|
444
444
|
|
445
|
-
remote: __remote_spec[modal._functions.
|
445
|
+
remote: __remote_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
|
446
446
|
|
447
447
|
class __remote_gen_spec(typing_extensions.Protocol[SUPERSELF]):
|
448
448
|
def __call__(self, /, *args, **kwargs) -> typing.Generator[typing.Any, None, None]:
|
@@ -469,7 +469,7 @@ class Function(
|
|
469
469
|
"""
|
470
470
|
...
|
471
471
|
|
472
|
-
class ___experimental_spawn_spec(typing_extensions.Protocol[
|
472
|
+
class ___experimental_spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
473
473
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
474
474
|
"""[Experimental] Calls the function with the given arguments, without waiting for the results.
|
475
475
|
|
@@ -493,7 +493,7 @@ class Function(
|
|
493
493
|
...
|
494
494
|
|
495
495
|
_experimental_spawn: ___experimental_spawn_spec[
|
496
|
-
modal._functions.
|
496
|
+
modal._functions.P, modal._functions.ReturnType, typing_extensions.Self
|
497
497
|
]
|
498
498
|
|
499
499
|
class ___spawn_map_inner_spec(typing_extensions.Protocol[P_INNER, SUPERSELF]):
|
@@ -502,7 +502,7 @@ class Function(
|
|
502
502
|
|
503
503
|
_spawn_map_inner: ___spawn_map_inner_spec[modal._functions.P, typing_extensions.Self]
|
504
504
|
|
505
|
-
class __spawn_spec(typing_extensions.Protocol[
|
505
|
+
class __spawn_spec(typing_extensions.Protocol[P_INNER, ReturnType_INNER, SUPERSELF]):
|
506
506
|
def __call__(self, /, *args: P_INNER.args, **kwargs: P_INNER.kwargs) -> FunctionCall[ReturnType_INNER]:
|
507
507
|
"""Calls the function with the given arguments, without waiting for the results.
|
508
508
|
|
@@ -523,7 +523,7 @@ class Function(
|
|
523
523
|
"""
|
524
524
|
...
|
525
525
|
|
526
|
-
spawn: __spawn_spec[modal._functions.
|
526
|
+
spawn: __spawn_spec[modal._functions.P, modal._functions.ReturnType, typing_extensions.Self]
|
527
527
|
|
528
528
|
def get_raw_f(self) -> collections.abc.Callable[..., typing.Any]:
|
529
529
|
"""Return the inner Python object wrapped by this Modal Function."""
|
@@ -673,9 +673,11 @@ async def _map_invocation_inputplane(
|
|
673
673
|
# any reason).
|
674
674
|
max_inputs_outstanding = MAX_INPUTS_OUTSTANDING_DEFAULT
|
675
675
|
|
676
|
-
#
|
676
|
+
# Set a default retry policy to construct an instance of _MapItemsManager.
|
677
|
+
# We'll update the retry policy with the actual user-specified retry policy
|
678
|
+
# from the server in the first MapStartOrContinue response.
|
677
679
|
retry_policy = api_pb2.FunctionRetryPolicy(
|
678
|
-
retries=0,
|
680
|
+
retries=0,
|
679
681
|
initial_delay_ms=1000,
|
680
682
|
max_delay_ms=1000,
|
681
683
|
backoff_coefficient=1.0,
|
@@ -771,10 +773,17 @@ async def _map_invocation_inputplane(
|
|
771
773
|
|
772
774
|
map_items_manager.handle_put_continue_response(response_items_idx_tuple)
|
773
775
|
|
776
|
+
# Set the function call id and actual retry policy with the data from the first response.
|
777
|
+
# This conditional is skipped for subsequent iterations of this for-loop.
|
774
778
|
if function_call_id is None:
|
775
779
|
function_call_id = response.function_call_id
|
776
780
|
function_call_id_received.set()
|
777
781
|
max_inputs_outstanding = response.max_inputs_outstanding or MAX_INPUTS_OUTSTANDING_DEFAULT
|
782
|
+
map_items_manager.set_retry_policy(response.retry_policy)
|
783
|
+
# Update the retry policy for the first batch of inputs.
|
784
|
+
# Subsequent batches will have the correct user-specified retry policy
|
785
|
+
# set by the updated _MapItemsManager.
|
786
|
+
map_items_manager.update_items_retry_policy(response.retry_policy)
|
778
787
|
yield
|
779
788
|
|
780
789
|
async def check_lost_inputs():
|
@@ -1475,6 +1484,9 @@ class _MapItemContext:
|
|
1475
1484
|
retry_count=self.retry_manager.retry_count,
|
1476
1485
|
)
|
1477
1486
|
|
1487
|
+
def set_retry_policy(self, retry_policy: api_pb2.FunctionRetryPolicy):
|
1488
|
+
self.retry_manager = RetryManager(retry_policy)
|
1489
|
+
|
1478
1490
|
def handle_retry_response(self, input_jwt: str):
|
1479
1491
|
self.input_jwt.set_result(input_jwt)
|
1480
1492
|
self.state = _MapItemState.WAITING_FOR_OUTPUT
|
@@ -1511,6 +1523,9 @@ class _MapItemsManager:
|
|
1511
1523
|
self._sync_client_retries_enabled = sync_client_retries_enabled
|
1512
1524
|
self._is_input_plane_instance = is_input_plane_instance
|
1513
1525
|
|
1526
|
+
def set_retry_policy(self, retry_policy: api_pb2.FunctionRetryPolicy):
|
1527
|
+
self._retry_policy = retry_policy
|
1528
|
+
|
1514
1529
|
async def add_items(self, items: list[api_pb2.FunctionPutInputsItem]):
|
1515
1530
|
for item in items:
|
1516
1531
|
# acquire semaphore to limit the number of inputs in progress
|
@@ -1540,6 +1555,10 @@ class _MapItemsManager:
|
|
1540
1555
|
async def prepare_items_for_retry(self, retriable_idxs: list[int]) -> list[api_pb2.FunctionRetryInputsItem]:
|
1541
1556
|
return [await self._item_context[idx].prepare_item_for_retry() for idx in retriable_idxs]
|
1542
1557
|
|
1558
|
+
def update_items_retry_policy(self, retry_policy: api_pb2.FunctionRetryPolicy):
|
1559
|
+
for ctx in self._item_context.values():
|
1560
|
+
ctx.set_retry_policy(retry_policy)
|
1561
|
+
|
1543
1562
|
def get_input_jwts_waiting_for_output(self) -> list[str]:
|
1544
1563
|
"""
|
1545
1564
|
Returns a list of input_jwts for inputs that are waiting for output.
|
@@ -406,6 +406,7 @@ class _MapItemContext:
|
|
406
406
|
...
|
407
407
|
|
408
408
|
async def prepare_item_for_retry(self) -> modal_proto.api_pb2.FunctionRetryInputsItem: ...
|
409
|
+
def set_retry_policy(self, retry_policy: modal_proto.api_pb2.FunctionRetryPolicy): ...
|
409
410
|
def handle_retry_response(self, input_jwt: str): ...
|
410
411
|
async def create_map_start_or_continue_item(self, idx: int) -> modal_proto.api_pb2.MapStartOrContinueItem: ...
|
411
412
|
|
@@ -422,11 +423,13 @@ class _MapItemsManager:
|
|
422
423
|
"""Initialize self. See help(type(self)) for accurate signature."""
|
423
424
|
...
|
424
425
|
|
426
|
+
def set_retry_policy(self, retry_policy: modal_proto.api_pb2.FunctionRetryPolicy): ...
|
425
427
|
async def add_items(self, items: list[modal_proto.api_pb2.FunctionPutInputsItem]): ...
|
426
428
|
async def add_items_inputplane(self, items: list[modal_proto.api_pb2.MapStartOrContinueItem]): ...
|
427
429
|
async def prepare_items_for_retry(
|
428
430
|
self, retriable_idxs: list[int]
|
429
431
|
) -> list[modal_proto.api_pb2.FunctionRetryInputsItem]: ...
|
432
|
+
def update_items_retry_policy(self, retry_policy: modal_proto.api_pb2.FunctionRetryPolicy): ...
|
430
433
|
def get_input_jwts_waiting_for_output(self) -> list[str]:
|
431
434
|
"""Returns a list of input_jwts for inputs that are waiting for output."""
|
432
435
|
...
|
@@ -618,7 +618,7 @@ message AttemptStartRequest {
|
|
618
618
|
|
619
619
|
message AttemptStartResponse {
|
620
620
|
string attempt_token = 1;
|
621
|
-
FunctionRetryPolicy retry_policy = 2;
|
621
|
+
FunctionRetryPolicy retry_policy = 2;
|
622
622
|
}
|
623
623
|
|
624
624
|
message AuthTokenGetRequest {
|
@@ -2167,7 +2167,7 @@ message MapStartOrContinueResponse {
|
|
2167
2167
|
string function_call_id = 2;
|
2168
2168
|
uint32 max_inputs_outstanding = 3;
|
2169
2169
|
repeated string attempt_tokens = 4;
|
2170
|
-
FunctionRetryPolicy retry_policy = 5;
|
2170
|
+
FunctionRetryPolicy retry_policy = 5;
|
2171
2171
|
}
|
2172
2172
|
|
2173
2173
|
message MethodDefinition {
|
@@ -1959,8 +1959,7 @@ class AttemptStartResponse(google.protobuf.message.Message):
|
|
1959
1959
|
RETRY_POLICY_FIELD_NUMBER: builtins.int
|
1960
1960
|
attempt_token: builtins.str
|
1961
1961
|
@property
|
1962
|
-
def retry_policy(self) -> global___FunctionRetryPolicy:
|
1963
|
-
"""TODO(ben-okeefe) TODO(nathan): Not currently used"""
|
1962
|
+
def retry_policy(self) -> global___FunctionRetryPolicy: ...
|
1964
1963
|
def __init__(
|
1965
1964
|
self,
|
1966
1965
|
*,
|
@@ -7007,8 +7006,7 @@ class MapStartOrContinueResponse(google.protobuf.message.Message):
|
|
7007
7006
|
@property
|
7008
7007
|
def attempt_tokens(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
|
7009
7008
|
@property
|
7010
|
-
def retry_policy(self) -> global___FunctionRetryPolicy:
|
7011
|
-
"""TODO(ben-okeefe): Not currently used"""
|
7009
|
+
def retry_policy(self) -> global___FunctionRetryPolicy: ...
|
7012
7010
|
def __init__(
|
7013
7011
|
self,
|
7014
7012
|
*,
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|