opensandbox 0.1.8.dev0__tar.gz → 0.1.8.dev2__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.
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/.gitignore +2 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/PKG-INFO +6 -5
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/README.md +5 -4
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/pyproject.toml +1 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/__init__.py +0 -4
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/converter/exception_converter.py +4 -1
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/converter/response_handler.py +16 -6
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/snapshots/delete_snapshots_snapshot_id.py +28 -8
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/snapshots/post_sandboxes_sandbox_id_snapshots.py +16 -8
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/async_redis_pool_store.py +101 -42
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/pool.py +0 -4
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/pool_async.py +11 -10
- opensandbox-0.1.8.dev2/src/opensandbox/pool_redis.py +27 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/redis_pool_store.py +47 -7
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/pool.py +11 -11
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/LICENSE +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/_async_pool_reconciler.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/_async_pool_store.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/_pool_reconciler.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/_pool_store.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/command_adapter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/converter/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/converter/command_model_converter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/converter/event_node.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/converter/execution_converter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/converter/execution_event_dispatcher.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/converter/filesystem_model_converter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/converter/metrics_model_converter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/converter/sandbox_model_converter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/egress_adapter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/factory.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/filesystem_adapter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/health_adapter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/metrics_adapter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/adapters/sandboxes_adapter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/api/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/api/policy/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/api/policy/get_policy.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/api/policy/patch_policy.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/client.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/errors.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/models/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/models/network_policy.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/models/network_policy_default_action.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/models/network_rule.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/models/network_rule_action.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/models/policy_status_response.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/py.typed +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/egress/types.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/code_interpreting/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/code_interpreting/create_code_context.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/code_interpreting/delete_context.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/code_interpreting/delete_contexts_by_language.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/code_interpreting/get_context.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/code_interpreting/interrupt_code.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/code_interpreting/list_contexts.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/code_interpreting/run_code.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/command/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/command/create_session.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/command/delete_session.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/command/get_background_command_logs.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/command/get_command_status.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/command/interrupt_command.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/command/run_command.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/command/run_in_session.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/filesystem/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/filesystem/chmod_files.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/filesystem/download_file.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/filesystem/get_files_info.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/filesystem/make_dirs.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/filesystem/remove_dirs.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/filesystem/remove_files.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/filesystem/rename_files.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/filesystem/replace_content.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/filesystem/search_files.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/filesystem/upload_file.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/health/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/health/ping.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/metric/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/metric/get_metrics.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/api/metric/watch_metrics.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/client.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/errors.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/chmod_files_body.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/code_context.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/code_context_request.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/command_status_response.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/create_session_request.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/create_session_response.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/error_response.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/file_info.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/file_metadata.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/get_files_info_response_200.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/make_dirs_body.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/metrics.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/permission.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/rename_file_item.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/replace_content_body.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/replace_file_content_item.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/run_code_request.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/run_command_request.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/run_command_request_envs.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/run_in_session_request.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/server_stream_event.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/server_stream_event_error.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/server_stream_event_results.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/server_stream_event_type.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/models/upload_file_body.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/py.typed +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/execd/types.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/sandboxes/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/sandboxes/delete_sandboxes_sandbox_id.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/sandboxes/get_sandboxes.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/sandboxes/get_sandboxes_sandbox_id.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/sandboxes/get_sandboxes_sandbox_id_endpoints_port.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/sandboxes/post_sandboxes.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/sandboxes/post_sandboxes_sandbox_id_pause.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/sandboxes/post_sandboxes_sandbox_id_renew_expiration.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/sandboxes/post_sandboxes_sandbox_id_resume.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/snapshots/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/snapshots/get_snapshots.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/api/snapshots/get_snapshots_snapshot_id.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/client.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/errors.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/create_sandbox_request.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/create_sandbox_request_env.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/create_sandbox_request_extensions.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/create_sandbox_request_metadata.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/create_sandbox_response.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/create_sandbox_response_metadata.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/create_snapshot_request.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/endpoint.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/endpoint_headers.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/error_response.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/host.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/image_spec.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/image_spec_auth.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/list_sandboxes_response.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/list_snapshots_response.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/network_policy.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/network_policy_default_action.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/network_rule.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/network_rule_action.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/ossfs.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/ossfs_version.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/pagination_info.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/platform_spec.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/platform_spec_arch.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/platform_spec_os.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/pvc.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/renew_sandbox_expiration_request.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/renew_sandbox_expiration_response.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/resource_limits.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/sandbox.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/sandbox_metadata.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/sandbox_status.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/snapshot.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/snapshot_status.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/models/volume.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/py.typed +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/api/lifecycle/types.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/config/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/config/connection.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/config/connection_sync.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/constants.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/exceptions/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/exceptions/sandbox.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/manager.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/models/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/models/execd.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/models/execd_sync.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/models/filesystem.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/models/sandboxes.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/pool_types.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/py.typed +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sandbox.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/services/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/services/command.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/services/egress.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/services/filesystem.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/services/health.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/services/metrics.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/services/sandbox.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/adapters/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/adapters/command_adapter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/adapters/converter/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/adapters/converter/execution_event_dispatcher.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/adapters/egress_adapter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/adapters/factory.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/adapters/filesystem_adapter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/adapters/health_adapter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/adapters/metrics_adapter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/adapters/sandboxes_adapter.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/manager.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/sandbox.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/services/__init__.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/services/command.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/services/egress.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/services/filesystem.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/services/health.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/services/metrics.py +0 -0
- {opensandbox-0.1.8.dev0 → opensandbox-0.1.8.dev2}/src/opensandbox/sync/services/sandbox.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: opensandbox
|
|
3
|
-
Version: 0.1.8.
|
|
3
|
+
Version: 0.1.8.dev2
|
|
4
4
|
Summary: OpenSandbox Python SDK - Secure, isolated execution environments
|
|
5
5
|
Project-URL: Homepage, https://open-sandbox.ai
|
|
6
6
|
Project-URL: Repository, https://github.com/alibaba/OpenSandbox
|
|
@@ -420,8 +420,9 @@ The store does not create or close Redis clients.
|
|
|
420
420
|
```python
|
|
421
421
|
import redis
|
|
422
422
|
|
|
423
|
-
from opensandbox import PoolCreationSpec,
|
|
423
|
+
from opensandbox import PoolCreationSpec, SandboxPoolSync
|
|
424
424
|
from opensandbox.config import ConnectionConfigSync
|
|
425
|
+
from opensandbox.pool_redis import RedisPoolStateStore
|
|
425
426
|
|
|
426
427
|
redis_client = redis.Redis.from_url(
|
|
427
428
|
"redis://user:password@redis.example.com:6379/0",
|
|
@@ -453,9 +454,9 @@ Notes:
|
|
|
453
454
|
lock owner and is not the pool identifier.
|
|
454
455
|
- All nodes sharing one pool must use the same creation and warmup definition. If
|
|
455
456
|
that definition changes, use a new `pool_name` or `key_prefix` and drain the old pool.
|
|
456
|
-
- `resize(max_idle)` can be called from any node. The
|
|
457
|
-
the shared state store
|
|
458
|
-
during reconcile.
|
|
457
|
+
- `resize(max_idle)` can be called from any node. The call returns after the new
|
|
458
|
+
idle target is stored in the shared state store; the current primary applies
|
|
459
|
+
replenish or shrink work during periodic reconcile.
|
|
459
460
|
- Use `resize(0)` and wait for `snapshot().idle_count == 0` to drain a distributed
|
|
460
461
|
idle buffer. `release_all_idle()` is only a best-effort cleanup pass in distributed
|
|
461
462
|
mode because another primary may put new idle sandboxes concurrently unless the
|
|
@@ -187,8 +187,9 @@ The store does not create or close Redis clients.
|
|
|
187
187
|
```python
|
|
188
188
|
import redis
|
|
189
189
|
|
|
190
|
-
from opensandbox import PoolCreationSpec,
|
|
190
|
+
from opensandbox import PoolCreationSpec, SandboxPoolSync
|
|
191
191
|
from opensandbox.config import ConnectionConfigSync
|
|
192
|
+
from opensandbox.pool_redis import RedisPoolStateStore
|
|
192
193
|
|
|
193
194
|
redis_client = redis.Redis.from_url(
|
|
194
195
|
"redis://user:password@redis.example.com:6379/0",
|
|
@@ -220,9 +221,9 @@ Notes:
|
|
|
220
221
|
lock owner and is not the pool identifier.
|
|
221
222
|
- All nodes sharing one pool must use the same creation and warmup definition. If
|
|
222
223
|
that definition changes, use a new `pool_name` or `key_prefix` and drain the old pool.
|
|
223
|
-
- `resize(max_idle)` can be called from any node. The
|
|
224
|
-
the shared state store
|
|
225
|
-
during reconcile.
|
|
224
|
+
- `resize(max_idle)` can be called from any node. The call returns after the new
|
|
225
|
+
idle target is stored in the shared state store; the current primary applies
|
|
226
|
+
replenish or shrink work during periodic reconcile.
|
|
226
227
|
- Use `resize(0)` and wait for `snapshot().idle_count == 0` to drain a distributed
|
|
227
228
|
idle buffer. `release_all_idle()` is only a best-effort cleanup pass in distributed
|
|
228
229
|
mode because another primary may put new idle sandboxes concurrently unless the
|
|
@@ -102,12 +102,10 @@ from importlib.metadata import version as _pkg_version
|
|
|
102
102
|
from opensandbox.manager import SandboxManager
|
|
103
103
|
from opensandbox.pool import (
|
|
104
104
|
AcquirePolicy,
|
|
105
|
-
AsyncRedisPoolStateStore,
|
|
106
105
|
AsyncSandboxPool,
|
|
107
106
|
InMemoryAsyncPoolStateStore,
|
|
108
107
|
InMemoryPoolStateStore,
|
|
109
108
|
PoolCreationSpec,
|
|
110
|
-
RedisPoolStateStore,
|
|
111
109
|
SandboxPool,
|
|
112
110
|
SandboxPoolAsync,
|
|
113
111
|
)
|
|
@@ -133,6 +131,4 @@ __all__ = [
|
|
|
133
131
|
"PoolCreationSpec",
|
|
134
132
|
"InMemoryAsyncPoolStateStore",
|
|
135
133
|
"InMemoryPoolStateStore",
|
|
136
|
-
"AsyncRedisPoolStateStore",
|
|
137
|
-
"RedisPoolStateStore",
|
|
138
134
|
]
|
|
@@ -234,8 +234,11 @@ def _parse_error_body(body: Any) -> SandboxError | None:
|
|
|
234
234
|
message=body,
|
|
235
235
|
)
|
|
236
236
|
|
|
237
|
-
#
|
|
237
|
+
# FastAPI HTTPException bodies are commonly wrapped as {"detail": {"code": ..., "message": ...}}.
|
|
238
238
|
if isinstance(body, dict):
|
|
239
|
+
if isinstance(body.get("detail"), dict):
|
|
240
|
+
body = body["detail"]
|
|
241
|
+
|
|
239
242
|
code: str | None = body.get("code")
|
|
240
243
|
message: str | None = body.get("message")
|
|
241
244
|
|
|
@@ -28,7 +28,7 @@ import logging
|
|
|
28
28
|
from http import HTTPStatus
|
|
29
29
|
from typing import Any, TypeVar
|
|
30
30
|
|
|
31
|
-
from opensandbox.exceptions import SandboxApiException
|
|
31
|
+
from opensandbox.exceptions import SandboxApiException, SandboxError
|
|
32
32
|
|
|
33
33
|
logger = logging.getLogger(__name__)
|
|
34
34
|
|
|
@@ -118,17 +118,27 @@ def handle_api_error(response_obj: Any, operation_name: str = "API call") -> Non
|
|
|
118
118
|
|
|
119
119
|
if status_code >= 300:
|
|
120
120
|
error_message = f"{operation_name} failed: HTTP {status_code}"
|
|
121
|
+
sandbox_error: SandboxError | None = None
|
|
121
122
|
|
|
122
123
|
if hasattr(response_obj, "parsed") and response_obj.parsed is not None:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
parsed = response_obj.parsed
|
|
125
|
+
parsed_code = getattr(parsed, "code", None)
|
|
126
|
+
parsed_message = getattr(parsed, "message", None)
|
|
127
|
+
|
|
128
|
+
if parsed_message:
|
|
129
|
+
error_message = f"{operation_name} failed: {parsed_message}"
|
|
130
|
+
elif parsed_code:
|
|
131
|
+
error_message = f"{operation_name} failed: {parsed_code}"
|
|
132
|
+
|
|
133
|
+
if parsed_code:
|
|
134
|
+
sandbox_error = SandboxError(
|
|
135
|
+
code=str(parsed_code),
|
|
136
|
+
message=str(parsed_message or ""),
|
|
126
137
|
)
|
|
127
|
-
elif hasattr(response_obj.parsed, "code"):
|
|
128
|
-
error_message = f"{operation_name} failed: {response_obj.parsed.code}"
|
|
129
138
|
|
|
130
139
|
raise SandboxApiException(
|
|
131
140
|
message=error_message,
|
|
132
141
|
status_code=status_code,
|
|
133
142
|
request_id=request_id,
|
|
143
|
+
error=sandbox_error,
|
|
134
144
|
)
|
|
@@ -91,8 +91,13 @@ def sync_detailed(
|
|
|
91
91
|
) -> Response[Any | ErrorResponse]:
|
|
92
92
|
"""Delete a snapshot
|
|
93
93
|
|
|
94
|
-
Delete a persistent sandbox snapshot by id. Snapshots that are still
|
|
95
|
-
deleted.
|
|
94
|
+
Delete a persistent sandbox snapshot by id. Snapshots that are still
|
|
95
|
+
being created cannot be deleted.
|
|
96
|
+
|
|
97
|
+
For Kubernetes-backed snapshots, deletion removes OpenSandbox metadata
|
|
98
|
+
and Kubernetes coordination resources, but does not guarantee removal
|
|
99
|
+
of pushed OCI images from the configured registry. Use registry
|
|
100
|
+
retention or garbage collection policies for image lifecycle cleanup.
|
|
96
101
|
|
|
97
102
|
Args:
|
|
98
103
|
snapshot_id (str):
|
|
@@ -123,8 +128,13 @@ def sync(
|
|
|
123
128
|
) -> Any | ErrorResponse | None:
|
|
124
129
|
"""Delete a snapshot
|
|
125
130
|
|
|
126
|
-
Delete a persistent sandbox snapshot by id. Snapshots that are still
|
|
127
|
-
deleted.
|
|
131
|
+
Delete a persistent sandbox snapshot by id. Snapshots that are still
|
|
132
|
+
being created cannot be deleted.
|
|
133
|
+
|
|
134
|
+
For Kubernetes-backed snapshots, deletion removes OpenSandbox metadata
|
|
135
|
+
and Kubernetes coordination resources, but does not guarantee removal
|
|
136
|
+
of pushed OCI images from the configured registry. Use registry
|
|
137
|
+
retention or garbage collection policies for image lifecycle cleanup.
|
|
128
138
|
|
|
129
139
|
Args:
|
|
130
140
|
snapshot_id (str):
|
|
@@ -150,8 +160,13 @@ async def asyncio_detailed(
|
|
|
150
160
|
) -> Response[Any | ErrorResponse]:
|
|
151
161
|
"""Delete a snapshot
|
|
152
162
|
|
|
153
|
-
Delete a persistent sandbox snapshot by id. Snapshots that are still
|
|
154
|
-
deleted.
|
|
163
|
+
Delete a persistent sandbox snapshot by id. Snapshots that are still
|
|
164
|
+
being created cannot be deleted.
|
|
165
|
+
|
|
166
|
+
For Kubernetes-backed snapshots, deletion removes OpenSandbox metadata
|
|
167
|
+
and Kubernetes coordination resources, but does not guarantee removal
|
|
168
|
+
of pushed OCI images from the configured registry. Use registry
|
|
169
|
+
retention or garbage collection policies for image lifecycle cleanup.
|
|
155
170
|
|
|
156
171
|
Args:
|
|
157
172
|
snapshot_id (str):
|
|
@@ -180,8 +195,13 @@ async def asyncio(
|
|
|
180
195
|
) -> Any | ErrorResponse | None:
|
|
181
196
|
"""Delete a snapshot
|
|
182
197
|
|
|
183
|
-
Delete a persistent sandbox snapshot by id. Snapshots that are still
|
|
184
|
-
deleted.
|
|
198
|
+
Delete a persistent sandbox snapshot by id. Snapshots that are still
|
|
199
|
+
being created cannot be deleted.
|
|
200
|
+
|
|
201
|
+
For Kubernetes-backed snapshots, deletion removes OpenSandbox metadata
|
|
202
|
+
and Kubernetes coordination resources, but does not guarantee removal
|
|
203
|
+
of pushed OCI images from the configured registry. Use registry
|
|
204
|
+
retention or garbage collection policies for image lifecycle cleanup.
|
|
185
205
|
|
|
186
206
|
Args:
|
|
187
207
|
snapshot_id (str):
|
|
@@ -115,8 +115,10 @@ def sync_detailed(
|
|
|
115
115
|
"""Create a snapshot from a sandbox
|
|
116
116
|
|
|
117
117
|
Create a persistent point-in-time snapshot from the sandbox's current state.
|
|
118
|
-
The
|
|
119
|
-
|
|
118
|
+
The source sandbox must be `Running`. The returned snapshot id identifies
|
|
119
|
+
the created artifact. Snapshot creation may temporarily pause the sandbox
|
|
120
|
+
while the runtime captures provider-supported state, then the source
|
|
121
|
+
sandbox continues running.
|
|
120
122
|
|
|
121
123
|
Args:
|
|
122
124
|
sandbox_id (str):
|
|
@@ -151,8 +153,10 @@ def sync(
|
|
|
151
153
|
"""Create a snapshot from a sandbox
|
|
152
154
|
|
|
153
155
|
Create a persistent point-in-time snapshot from the sandbox's current state.
|
|
154
|
-
The
|
|
155
|
-
|
|
156
|
+
The source sandbox must be `Running`. The returned snapshot id identifies
|
|
157
|
+
the created artifact. Snapshot creation may temporarily pause the sandbox
|
|
158
|
+
while the runtime captures provider-supported state, then the source
|
|
159
|
+
sandbox continues running.
|
|
156
160
|
|
|
157
161
|
Args:
|
|
158
162
|
sandbox_id (str):
|
|
@@ -182,8 +186,10 @@ async def asyncio_detailed(
|
|
|
182
186
|
"""Create a snapshot from a sandbox
|
|
183
187
|
|
|
184
188
|
Create a persistent point-in-time snapshot from the sandbox's current state.
|
|
185
|
-
The
|
|
186
|
-
|
|
189
|
+
The source sandbox must be `Running`. The returned snapshot id identifies
|
|
190
|
+
the created artifact. Snapshot creation may temporarily pause the sandbox
|
|
191
|
+
while the runtime captures provider-supported state, then the source
|
|
192
|
+
sandbox continues running.
|
|
187
193
|
|
|
188
194
|
Args:
|
|
189
195
|
sandbox_id (str):
|
|
@@ -216,8 +222,10 @@ async def asyncio(
|
|
|
216
222
|
"""Create a snapshot from a sandbox
|
|
217
223
|
|
|
218
224
|
Create a persistent point-in-time snapshot from the sandbox's current state.
|
|
219
|
-
The
|
|
220
|
-
|
|
225
|
+
The source sandbox must be `Running`. The returned snapshot id identifies
|
|
226
|
+
the created artifact. Snapshot creation may temporarily pause the sandbox
|
|
227
|
+
while the runtime captures provider-supported state, then the source
|
|
228
|
+
sandbox continues running.
|
|
221
229
|
|
|
222
230
|
Args:
|
|
223
231
|
sandbox_id (str):
|
|
@@ -20,17 +20,26 @@ from __future__ import annotations
|
|
|
20
20
|
import base64
|
|
21
21
|
from collections.abc import Awaitable, Callable
|
|
22
22
|
from datetime import datetime, timedelta, timezone
|
|
23
|
-
from typing import Any, TypeVar
|
|
23
|
+
from typing import Any, TypeVar, cast
|
|
24
24
|
|
|
25
25
|
from opensandbox.exceptions import PoolStateStoreUnavailableException
|
|
26
26
|
from opensandbox.pool_types import IdleEntry, StoreCounters
|
|
27
27
|
from opensandbox.redis_pool_store import (
|
|
28
|
+
_REQUIRED_REDIS_METHODS,
|
|
29
|
+
Redis,
|
|
28
30
|
RedisPoolStateStore,
|
|
29
31
|
_decode,
|
|
30
32
|
_millis,
|
|
31
33
|
_validate_owner_and_ttl,
|
|
32
34
|
)
|
|
33
35
|
|
|
36
|
+
try:
|
|
37
|
+
from redis.asyncio import Redis as AsyncRedis
|
|
38
|
+
except ImportError as exc: # pragma: no cover
|
|
39
|
+
raise ImportError(
|
|
40
|
+
'Install opensandbox[pool-redis] to use opensandbox.pool_redis'
|
|
41
|
+
) from exc
|
|
42
|
+
|
|
34
43
|
T = TypeVar("T")
|
|
35
44
|
|
|
36
45
|
|
|
@@ -39,7 +48,8 @@ class AsyncRedisPoolStateStore:
|
|
|
39
48
|
|
|
40
49
|
DEFAULT_KEY_PREFIX = RedisPoolStateStore.DEFAULT_KEY_PREFIX
|
|
41
50
|
|
|
42
|
-
def __init__(self, redis:
|
|
51
|
+
def __init__(self, redis: AsyncRedis, key_prefix: str = DEFAULT_KEY_PREFIX) -> None:
|
|
52
|
+
_validate_async_redis_client(redis)
|
|
43
53
|
self._redis = redis
|
|
44
54
|
self._key_prefix = key_prefix
|
|
45
55
|
self._default_idle_ttl = timedelta(hours=24)
|
|
@@ -48,11 +58,14 @@ class AsyncRedisPoolStateStore:
|
|
|
48
58
|
result = await self._execute(
|
|
49
59
|
"try_take_idle",
|
|
50
60
|
pool_name,
|
|
51
|
-
lambda:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
lambda: cast(
|
|
62
|
+
Awaitable[Any],
|
|
63
|
+
self._redis.eval(
|
|
64
|
+
RedisPoolStateStore._TAKE_IDLE_SCRIPT,
|
|
65
|
+
2,
|
|
66
|
+
self._idle_list_key(pool_name),
|
|
67
|
+
self._idle_expires_key(pool_name),
|
|
68
|
+
),
|
|
56
69
|
),
|
|
57
70
|
)
|
|
58
71
|
return _decode(result) if result is not None else None
|
|
@@ -64,13 +77,16 @@ class AsyncRedisPoolStateStore:
|
|
|
64
77
|
await self._execute(
|
|
65
78
|
"put_idle",
|
|
66
79
|
pool_name,
|
|
67
|
-
lambda:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
lambda: cast(
|
|
81
|
+
Awaitable[Any],
|
|
82
|
+
self._redis.eval(
|
|
83
|
+
RedisPoolStateStore._PUT_IDLE_SCRIPT,
|
|
84
|
+
2,
|
|
85
|
+
self._idle_list_key(pool_name),
|
|
86
|
+
self._idle_expires_key(pool_name),
|
|
87
|
+
sandbox_id,
|
|
88
|
+
str(ttl_millis),
|
|
89
|
+
),
|
|
74
90
|
),
|
|
75
91
|
)
|
|
76
92
|
|
|
@@ -79,8 +95,14 @@ class AsyncRedisPoolStateStore:
|
|
|
79
95
|
"remove_idle",
|
|
80
96
|
pool_name,
|
|
81
97
|
lambda: _gather_tuple(
|
|
82
|
-
|
|
83
|
-
|
|
98
|
+
cast(
|
|
99
|
+
Awaitable[Any],
|
|
100
|
+
self._redis.hdel(self._idle_expires_key(pool_name), sandbox_id),
|
|
101
|
+
),
|
|
102
|
+
cast(
|
|
103
|
+
Awaitable[Any],
|
|
104
|
+
self._redis.lrem(self._idle_list_key(pool_name), 0, sandbox_id),
|
|
105
|
+
),
|
|
84
106
|
),
|
|
85
107
|
)
|
|
86
108
|
|
|
@@ -109,12 +131,15 @@ class AsyncRedisPoolStateStore:
|
|
|
109
131
|
result = await self._execute(
|
|
110
132
|
"renew_primary_lock",
|
|
111
133
|
pool_name,
|
|
112
|
-
lambda:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
134
|
+
lambda: cast(
|
|
135
|
+
Awaitable[Any],
|
|
136
|
+
self._redis.eval(
|
|
137
|
+
RedisPoolStateStore._RENEW_LOCK_SCRIPT,
|
|
138
|
+
1,
|
|
139
|
+
self._primary_lock_key(pool_name),
|
|
140
|
+
owner_id,
|
|
141
|
+
str(max(1, _millis(ttl))),
|
|
142
|
+
),
|
|
118
143
|
),
|
|
119
144
|
)
|
|
120
145
|
return result == 1 or result == b"1"
|
|
@@ -123,11 +148,14 @@ class AsyncRedisPoolStateStore:
|
|
|
123
148
|
await self._execute(
|
|
124
149
|
"release_primary_lock",
|
|
125
150
|
pool_name,
|
|
126
|
-
lambda:
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
151
|
+
lambda: cast(
|
|
152
|
+
Awaitable[Any],
|
|
153
|
+
self._redis.eval(
|
|
154
|
+
RedisPoolStateStore._RELEASE_LOCK_SCRIPT,
|
|
155
|
+
1,
|
|
156
|
+
self._primary_lock_key(pool_name),
|
|
157
|
+
owner_id,
|
|
158
|
+
),
|
|
131
159
|
),
|
|
132
160
|
)
|
|
133
161
|
|
|
@@ -135,35 +163,52 @@ class AsyncRedisPoolStateStore:
|
|
|
135
163
|
await self._execute(
|
|
136
164
|
"reap_expired_idle",
|
|
137
165
|
pool_name,
|
|
138
|
-
lambda:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
166
|
+
lambda: cast(
|
|
167
|
+
Awaitable[Any],
|
|
168
|
+
self._redis.eval(
|
|
169
|
+
RedisPoolStateStore._REAP_EXPIRED_SCRIPT,
|
|
170
|
+
2,
|
|
171
|
+
self._idle_list_key(pool_name),
|
|
172
|
+
self._idle_expires_key(pool_name),
|
|
173
|
+
),
|
|
143
174
|
),
|
|
144
175
|
)
|
|
145
176
|
|
|
146
177
|
async def snapshot_counters(self, pool_name: str) -> StoreCounters:
|
|
147
178
|
async def op() -> StoreCounters:
|
|
148
|
-
|
|
179
|
+
idle_count = cast(
|
|
180
|
+
int,
|
|
181
|
+
await cast(
|
|
182
|
+
Awaitable[Any],
|
|
183
|
+
self._redis.hlen(self._idle_expires_key(pool_name)),
|
|
184
|
+
),
|
|
185
|
+
)
|
|
149
186
|
return StoreCounters(
|
|
150
|
-
idle_count=
|
|
187
|
+
idle_count=idle_count
|
|
151
188
|
)
|
|
152
189
|
|
|
153
190
|
return await self._execute("snapshot_counters", pool_name, op)
|
|
154
191
|
|
|
155
192
|
async def snapshot_idle_entries(self, pool_name: str) -> list[IdleEntry]:
|
|
156
193
|
async def op() -> list[IdleEntry]:
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
194
|
+
raw_ids = cast(
|
|
195
|
+
list[Any],
|
|
196
|
+
await cast(
|
|
197
|
+
Awaitable[Any],
|
|
198
|
+
self._redis.lrange(self._idle_list_key(pool_name), 0, -1),
|
|
199
|
+
),
|
|
200
|
+
)
|
|
201
|
+
ids = [_decode(v) for v in raw_ids]
|
|
202
|
+
raw_expires_by_id = cast(
|
|
203
|
+
dict[Any, Any],
|
|
204
|
+
await cast(
|
|
205
|
+
Awaitable[Any],
|
|
206
|
+
self._redis.hgetall(self._idle_expires_key(pool_name)),
|
|
207
|
+
),
|
|
208
|
+
)
|
|
162
209
|
expires_by_id = {
|
|
163
210
|
_decode(k): _decode(v)
|
|
164
|
-
for k, v in (
|
|
165
|
-
await self._redis.hgetall(self._idle_expires_key(pool_name))
|
|
166
|
-
).items()
|
|
211
|
+
for k, v in raw_expires_by_id.items()
|
|
167
212
|
}
|
|
168
213
|
entries: list[IdleEntry] = []
|
|
169
214
|
for sandbox_id in ids:
|
|
@@ -267,3 +312,17 @@ async def _gather_tuple(*awaitables: Awaitable[Any]) -> tuple[Any, ...]:
|
|
|
267
312
|
import asyncio
|
|
268
313
|
|
|
269
314
|
return tuple(await asyncio.gather(*awaitables))
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def _validate_async_redis_client(redis: Any) -> None:
|
|
318
|
+
if isinstance(redis, Redis) or not isinstance(redis, AsyncRedis):
|
|
319
|
+
raise TypeError(
|
|
320
|
+
"AsyncRedisPoolStateStore requires a redis.asyncio.Redis client; "
|
|
321
|
+
"use RedisPoolStateStore for redis.Redis"
|
|
322
|
+
)
|
|
323
|
+
for method_name in _REQUIRED_REDIS_METHODS:
|
|
324
|
+
method = getattr(redis, method_name, None)
|
|
325
|
+
if not callable(method):
|
|
326
|
+
raise TypeError(
|
|
327
|
+
f"AsyncRedisPoolStateStore requires a Redis client with callable {method_name}()"
|
|
328
|
+
)
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
|
|
18
18
|
from opensandbox._async_pool_store import InMemoryAsyncPoolStateStore
|
|
19
19
|
from opensandbox._pool_store import InMemoryPoolStateStore
|
|
20
|
-
from opensandbox.async_redis_pool_store import AsyncRedisPoolStateStore
|
|
21
20
|
from opensandbox.pool_async import AsyncSandboxPool, SandboxPoolAsync
|
|
22
21
|
from opensandbox.pool_types import (
|
|
23
22
|
AcquirePolicy,
|
|
@@ -32,7 +31,6 @@ from opensandbox.pool_types import (
|
|
|
32
31
|
PoolStateStore,
|
|
33
32
|
StoreCounters,
|
|
34
33
|
)
|
|
35
|
-
from opensandbox.redis_pool_store import RedisPoolStateStore
|
|
36
34
|
from opensandbox.sync.pool import SandboxPoolSync
|
|
37
35
|
|
|
38
36
|
SandboxPool = SandboxPoolSync
|
|
@@ -41,7 +39,6 @@ __all__ = [
|
|
|
41
39
|
"AcquirePolicy",
|
|
42
40
|
"AsyncPoolConfig",
|
|
43
41
|
"AsyncPoolStateStore",
|
|
44
|
-
"AsyncRedisPoolStateStore",
|
|
45
42
|
"AsyncSandboxPool",
|
|
46
43
|
"IdleEntry",
|
|
47
44
|
"InMemoryAsyncPoolStateStore",
|
|
@@ -52,7 +49,6 @@ __all__ = [
|
|
|
52
49
|
"PoolSnapshot",
|
|
53
50
|
"PoolState",
|
|
54
51
|
"PoolStateStore",
|
|
55
|
-
"RedisPoolStateStore",
|
|
56
52
|
"SandboxPoolAsync",
|
|
57
53
|
"SandboxPool",
|
|
58
54
|
"SandboxPoolSync",
|
|
@@ -135,10 +135,9 @@ class SandboxPoolAsync:
|
|
|
135
135
|
await self._state_store.set_idle_entry_ttl(
|
|
136
136
|
self._config.pool_name, self._config.idle_timeout
|
|
137
137
|
)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
)
|
|
138
|
+
await self._state_store.set_max_idle(
|
|
139
|
+
self._config.pool_name, self._config.max_idle
|
|
140
|
+
)
|
|
142
141
|
stop_event = asyncio.Event()
|
|
143
142
|
self._stop_event = stop_event
|
|
144
143
|
self._lifecycle_state = PoolLifecycleState.RUNNING
|
|
@@ -220,11 +219,6 @@ class SandboxPoolAsync:
|
|
|
220
219
|
raise ValueError("max_idle must be >= 0")
|
|
221
220
|
await self._state_store.set_max_idle(self._config.pool_name, max_idle)
|
|
222
221
|
self._current_max_idle = max_idle
|
|
223
|
-
if self._lifecycle_state == PoolLifecycleState.RUNNING:
|
|
224
|
-
asyncio.create_task(
|
|
225
|
-
self._run_reconcile_tick(),
|
|
226
|
-
name=f"sandbox-pool-resize-{self._config.pool_name}",
|
|
227
|
-
)
|
|
228
222
|
|
|
229
223
|
async def release_all_idle(self) -> int:
|
|
230
224
|
pool_name = self._config.pool_name
|
|
@@ -434,7 +428,14 @@ class SandboxPoolAsync:
|
|
|
434
428
|
skip_health_check=self._config.acquire_skip_health_check,
|
|
435
429
|
)
|
|
436
430
|
if sandbox_timeout is not None:
|
|
437
|
-
|
|
431
|
+
try:
|
|
432
|
+
await sandbox.renew(sandbox_timeout)
|
|
433
|
+
except BaseException:
|
|
434
|
+
try:
|
|
435
|
+
await sandbox.kill()
|
|
436
|
+
finally:
|
|
437
|
+
await sandbox.close()
|
|
438
|
+
raise
|
|
438
439
|
return sandbox
|
|
439
440
|
|
|
440
441
|
async def _resolve_max_idle(self) -> int:
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2025 Alibaba Group Holding Ltd.
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
"""Redis-backed sandbox pool state stores.
|
|
17
|
+
|
|
18
|
+
Install ``opensandbox[pool-redis]`` and pass a caller-managed redis-py client.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from opensandbox.async_redis_pool_store import AsyncRedisPoolStateStore
|
|
22
|
+
from opensandbox.redis_pool_store import RedisPoolStateStore
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"AsyncRedisPoolStateStore",
|
|
26
|
+
"RedisPoolStateStore",
|
|
27
|
+
]
|