modal 1.1.1.dev6__tar.gz → 1.1.1.dev9__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 modal might be problematic. Click here for more details.
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/PKG-INFO +1 -1
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/blob_utils.py +16 -21
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/function_utils.py +2 -2
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/client.pyi +2 -2
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/experimental/__init__.py +1 -1
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/experimental/flash.py +17 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/experimental/flash.pyi +19 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal.egg-info/PKG-INFO +1 -1
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/api.proto +2 -1
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/api_pb2.py +503 -503
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/api_pb2.pyi +4 -4
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_version/__init__.py +1 -1
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/LICENSE +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/README.md +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/__init__.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/__main__.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_clustered_functions.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_clustered_functions.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_container_entrypoint.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_functions.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_ipython.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_location.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_object.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_output.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_partial_function.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_pty.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_resolver.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_resources.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_runtime/__init__.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_runtime/asgi.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_runtime/container_io_manager.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_runtime/container_io_manager.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_runtime/execution_context.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_runtime/execution_context.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_runtime/gpu_memory_snapshot.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_runtime/telemetry.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_runtime/user_code_imports.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_serialization.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_traceback.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_tunnel.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_tunnel.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_type_manager.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/__init__.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/app_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/async_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/auth_token_manager.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/bytes_io_segment_payload.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/deprecation.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/docker_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/git_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/grpc_testing.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/grpc_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/hash_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/http_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/jwt_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/logger.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/mount_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/name_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/package_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/pattern_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/rand_pb_testing.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/shell_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_utils/time_utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_vendor/__init__.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_vendor/a2wsgi_wsgi.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_vendor/cloudpickle.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_vendor/tblib.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/_watcher.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/app.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/app.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/call_graph.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/__init__.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/_download.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/_traceback.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/app.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/cluster.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/config.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/container.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/dict.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/entry_point.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/environment.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/import_refs.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/launch.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/network_file_system.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/profile.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/programs/__init__.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/programs/run_jupyter.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/programs/vscode.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/queues.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/run.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/secret.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/token.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/utils.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cli/volume.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/client.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cloud_bucket_mount.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cloud_bucket_mount.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cls.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/cls.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/config.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/container_process.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/container_process.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/dict.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/dict.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/environments.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/environments.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/exception.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/experimental/ipython.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/file_io.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/file_io.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/file_pattern_matcher.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/functions.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/functions.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/gpu.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/image.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/image.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/io_streams.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/io_streams.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/mount.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/mount.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/network_file_system.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/network_file_system.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/object.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/object.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/output.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/parallel_map.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/parallel_map.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/partial_function.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/partial_function.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/proxy.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/proxy.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/py.typed +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/queue.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/queue.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/requirements/2023.12.312.txt +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/requirements/2023.12.txt +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/requirements/2024.04.txt +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/requirements/2024.10.txt +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/requirements/2025.06.txt +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/requirements/PREVIEW.txt +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/requirements/README.md +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/requirements/base-images.json +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/retries.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/runner.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/runner.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/running_app.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/sandbox.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/sandbox.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/schedule.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/scheduler_placement.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/secret.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/secret.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/serving.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/serving.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/snapshot.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/snapshot.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/stream_type.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/token_flow.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/token_flow.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/volume.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal/volume.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal.egg-info/SOURCES.txt +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal.egg-info/dependency_links.txt +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal.egg-info/entry_points.txt +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal.egg-info/requires.txt +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal.egg-info/top_level.txt +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_docs/__init__.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_docs/gen_cli_docs.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_docs/gen_reference_docs.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_docs/mdmd/__init__.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_docs/mdmd/mdmd.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_docs/mdmd/signatures.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/__init__.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/api_grpc.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/api_pb2_grpc.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/api_pb2_grpc.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/modal_api_grpc.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/modal_options_grpc.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/options.proto +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/options_grpc.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/options_pb2.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/options_pb2.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/options_pb2_grpc.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/options_pb2_grpc.pyi +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_proto/py.typed +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/modal_version/__main__.py +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/pyproject.toml +0 -0
- {modal-1.1.1.dev6 → modal-1.1.1.dev9}/setup.cfg +0 -0
|
@@ -188,16 +188,10 @@ def get_content_length(data: BinaryIO) -> int:
|
|
|
188
188
|
return content_length - pos
|
|
189
189
|
|
|
190
190
|
|
|
191
|
-
async def
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
latency_ms = (time.monotonic_ns() - t0) // 1_000_000
|
|
196
|
-
return latency_ms
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
async def _blob_upload_with_fallback(items, blob_ids: list[str], callback) -> tuple[str, bool, int]:
|
|
200
|
-
r2_latency_ms = 0
|
|
191
|
+
async def _blob_upload_with_fallback(
|
|
192
|
+
items, blob_ids: list[str], callback, content_length: int
|
|
193
|
+
) -> tuple[str, bool, int]:
|
|
194
|
+
r2_throughput_bytes_s = 0
|
|
201
195
|
r2_failed = False
|
|
202
196
|
for idx, (item, blob_id) in enumerate(zip(items, blob_ids)):
|
|
203
197
|
# We want to default to R2 95% of the time and S3 5% of the time.
|
|
@@ -206,14 +200,13 @@ async def _blob_upload_with_fallback(items, blob_ids: list[str], callback) -> tu
|
|
|
206
200
|
continue
|
|
207
201
|
try:
|
|
208
202
|
if blob_id.endswith(":r2"):
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
)
|
|
203
|
+
t0 = time.monotonic_ns()
|
|
204
|
+
await callback(item)
|
|
205
|
+
dt_ns = time.monotonic_ns() - t0
|
|
206
|
+
r2_throughput_bytes_s = (content_length * 1_000_000_000) // max(dt_ns, 1)
|
|
214
207
|
else:
|
|
215
208
|
await callback(item)
|
|
216
|
-
return blob_id, r2_failed,
|
|
209
|
+
return blob_id, r2_failed, r2_throughput_bytes_s
|
|
217
210
|
except Exception as _:
|
|
218
211
|
if blob_id.endswith(":r2"):
|
|
219
212
|
r2_failed = True
|
|
@@ -251,10 +244,11 @@ async def _blob_upload(
|
|
|
251
244
|
progress_report_cb=progress_report_cb,
|
|
252
245
|
)
|
|
253
246
|
|
|
254
|
-
blob_id, r2_failed,
|
|
247
|
+
blob_id, r2_failed, r2_throughput_bytes_s = await _blob_upload_with_fallback(
|
|
255
248
|
resp.multiparts.items,
|
|
256
249
|
resp.blob_ids,
|
|
257
250
|
upload_multipart_upload,
|
|
251
|
+
content_length=content_length,
|
|
258
252
|
)
|
|
259
253
|
else:
|
|
260
254
|
from .bytes_io_segment_payload import BytesIOSegmentPayload
|
|
@@ -271,16 +265,17 @@ async def _blob_upload(
|
|
|
271
265
|
content_md5_b64=upload_hashes.md5_base64,
|
|
272
266
|
)
|
|
273
267
|
|
|
274
|
-
blob_id, r2_failed,
|
|
268
|
+
blob_id, r2_failed, r2_throughput_bytes_s = await _blob_upload_with_fallback(
|
|
275
269
|
resp.upload_urls.items,
|
|
276
270
|
resp.blob_ids,
|
|
277
271
|
upload_to_s3_url,
|
|
272
|
+
content_length=content_length,
|
|
278
273
|
)
|
|
279
274
|
|
|
280
275
|
if progress_report_cb:
|
|
281
276
|
progress_report_cb(complete=True)
|
|
282
277
|
|
|
283
|
-
return blob_id, r2_failed,
|
|
278
|
+
return blob_id, r2_failed, r2_throughput_bytes_s
|
|
284
279
|
|
|
285
280
|
|
|
286
281
|
async def blob_upload_with_r2_failure_info(payload: bytes, stub: ModalClientModal) -> tuple[str, bool, int]:
|
|
@@ -291,13 +286,13 @@ async def blob_upload_with_r2_failure_info(payload: bytes, stub: ModalClientModa
|
|
|
291
286
|
logger.warning("Blob uploading string, not bytes - auto-encoding as utf8")
|
|
292
287
|
payload = payload.encode("utf8")
|
|
293
288
|
upload_hashes = get_upload_hashes(payload)
|
|
294
|
-
blob_id, r2_failed,
|
|
289
|
+
blob_id, r2_failed, r2_throughput_bytes_s = await _blob_upload(upload_hashes, payload, stub)
|
|
295
290
|
dur_s = max(time.time() - t0, 0.001) # avoid division by zero
|
|
296
291
|
throughput_mib_s = (size_mib) / dur_s
|
|
297
292
|
logger.debug(
|
|
298
293
|
f"Uploaded large blob of size {size_mib:.2f} MiB ({throughput_mib_s:.2f} MiB/s, total {dur_s:.2f}s). {blob_id}"
|
|
299
294
|
)
|
|
300
|
-
return blob_id, r2_failed,
|
|
295
|
+
return blob_id, r2_failed, r2_throughput_bytes_s
|
|
301
296
|
|
|
302
297
|
|
|
303
298
|
async def blob_upload(payload: bytes, stub: ModalClientModal) -> str:
|
|
@@ -563,7 +563,7 @@ async def _create_input(
|
|
|
563
563
|
args_serialized = serialize((args, kwargs))
|
|
564
564
|
|
|
565
565
|
if should_upload(len(args_serialized), max_object_size_bytes, function_call_invocation_type):
|
|
566
|
-
args_blob_id, r2_failed,
|
|
566
|
+
args_blob_id, r2_failed, r2_throughput_bytes_s = await blob_upload_with_r2_failure_info(args_serialized, stub)
|
|
567
567
|
return api_pb2.FunctionPutInputsItem(
|
|
568
568
|
input=api_pb2.FunctionInput(
|
|
569
569
|
args_blob_id=args_blob_id,
|
|
@@ -572,7 +572,7 @@ async def _create_input(
|
|
|
572
572
|
),
|
|
573
573
|
idx=idx,
|
|
574
574
|
r2_failed=r2_failed,
|
|
575
|
-
|
|
575
|
+
r2_throughput_bytes_s=r2_throughput_bytes_s,
|
|
576
576
|
)
|
|
577
577
|
else:
|
|
578
578
|
return api_pb2.FunctionPutInputsItem(
|
|
@@ -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.1.
|
|
36
|
+
version: str = "1.1.1.dev9",
|
|
37
37
|
):
|
|
38
38
|
"""mdmd:hidden
|
|
39
39
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -163,7 +163,7 @@ class Client:
|
|
|
163
163
|
server_url: str,
|
|
164
164
|
client_type: int,
|
|
165
165
|
credentials: typing.Optional[tuple[str, str]],
|
|
166
|
-
version: str = "1.1.1.
|
|
166
|
+
version: str = "1.1.1.dev9",
|
|
167
167
|
):
|
|
168
168
|
"""mdmd:hidden
|
|
169
169
|
The Modal client object is not intended to be instantiated directly by users.
|
|
@@ -20,7 +20,7 @@ from ..cls import _Cls, _Obj
|
|
|
20
20
|
from ..exception import InvalidError
|
|
21
21
|
from ..image import DockerfileSpec, ImageBuilderVersion, _Image, _ImageRegistryConfig
|
|
22
22
|
from ..secret import _Secret
|
|
23
|
-
from .flash import flash_forward, flash_prometheus_autoscaler # noqa: F401
|
|
23
|
+
from .flash import flash_forward, flash_get_containers, flash_prometheus_autoscaler # noqa: F401
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
def stop_fetching_inputs():
|
|
@@ -447,3 +447,20 @@ async def flash_prometheus_autoscaler(
|
|
|
447
447
|
)
|
|
448
448
|
await autoscaler.start()
|
|
449
449
|
return autoscaler
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
@synchronizer.create_blocking
|
|
453
|
+
async def flash_get_containers(app_name: str, cls_name: str) -> list[dict[str, Any]]:
|
|
454
|
+
"""
|
|
455
|
+
Return a list of flash containers for a deployed Flash service.
|
|
456
|
+
|
|
457
|
+
This is a highly experimental method that can break or be removed at any time without warning.
|
|
458
|
+
Do not use this method unless explicitly instructed to do so by Modal support.
|
|
459
|
+
"""
|
|
460
|
+
client = await _Client.from_env()
|
|
461
|
+
fn = _Cls.from_name(app_name, cls_name)._class_service_function
|
|
462
|
+
assert fn is not None
|
|
463
|
+
await fn.hydrate(client=client)
|
|
464
|
+
req = api_pb2.FlashContainerListRequest(function_id=fn.object_id)
|
|
465
|
+
resp = await retry_transient_errors(client.stub.FlashContainerList, req)
|
|
466
|
+
return resp.containers
|
|
@@ -250,3 +250,22 @@ class __flash_prometheus_autoscaler_spec(typing_extensions.Protocol):
|
|
|
250
250
|
...
|
|
251
251
|
|
|
252
252
|
flash_prometheus_autoscaler: __flash_prometheus_autoscaler_spec
|
|
253
|
+
|
|
254
|
+
class __flash_get_containers_spec(typing_extensions.Protocol):
|
|
255
|
+
def __call__(self, /, app_name: str, cls_name: str) -> list[dict[str, typing.Any]]:
|
|
256
|
+
"""Return a list of flash containers for a deployed Flash service.
|
|
257
|
+
|
|
258
|
+
This is a highly experimental method that can break or be removed at any time without warning.
|
|
259
|
+
Do not use this method unless explicitly instructed to do so by Modal support.
|
|
260
|
+
"""
|
|
261
|
+
...
|
|
262
|
+
|
|
263
|
+
async def aio(self, /, app_name: str, cls_name: str) -> list[dict[str, typing.Any]]:
|
|
264
|
+
"""Return a list of flash containers for a deployed Flash service.
|
|
265
|
+
|
|
266
|
+
This is a highly experimental method that can break or be removed at any time without warning.
|
|
267
|
+
Do not use this method unless explicitly instructed to do so by Modal support.
|
|
268
|
+
"""
|
|
269
|
+
...
|
|
270
|
+
|
|
271
|
+
flash_get_containers: __flash_get_containers_spec
|
|
@@ -1816,7 +1816,8 @@ message FunctionPutInputsItem {
|
|
|
1816
1816
|
int32 idx = 1;
|
|
1817
1817
|
FunctionInput input = 2;
|
|
1818
1818
|
bool r2_failed = 3;
|
|
1819
|
-
|
|
1819
|
+
reserved 4; // r2_latency_ms
|
|
1820
|
+
uint64 r2_throughput_bytes_s = 5;
|
|
1820
1821
|
}
|
|
1821
1822
|
|
|
1822
1823
|
message FunctionPutInputsRequest {
|