daytona 0.218.0 → 0.220.0
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.
- checksums.yaml +4 -4
- data/lib/daytona/common/daytona.rb +9 -0
- data/lib/daytona/daytona.rb +32 -8
- data/lib/daytona/sandbox.rb +31 -0
- data/lib/daytona/sdk/errors.rb +11 -0
- data/lib/daytona/sdk/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6c916e09a640a2761766f1a78652af5821f19a1a123e819844372d87651ca7fc
|
|
4
|
+
data.tar.gz: 486825b3ac58633a87e865a51ad51cdfc42f8bcd1a50f336b83cd43f90aa2856
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 83c22f64c8aaaf2522945b4fdd7ee1ac6f8fd6f96657027f0e445428ec1907cce96f0f112caee3213ac653ad88a8bca701b0447ce6851451438dca5b834b0576
|
|
7
|
+
data.tar.gz: 7db19827791d02beea4c549c6f53aaa85748504056027f5c0636caaf86a87c18f1017e9ce0c761e1f644da3b30a39dc988c3f09691dea14ee138fe1b834c17f6
|
|
@@ -69,6 +69,9 @@ module Daytona
|
|
|
69
69
|
# @return [Integer, nil] Time to live in minutes (0 to disable)
|
|
70
70
|
attr_accessor :ttl_minutes
|
|
71
71
|
|
|
72
|
+
# @return [Integer, nil] Minutes to wait for runner assignment before the API auto-destroys the sandbox
|
|
73
|
+
attr_accessor :queue_timeout
|
|
74
|
+
|
|
72
75
|
# @return [Boolean, nil] Whether the Sandbox should be ephemeral
|
|
73
76
|
attr_accessor :ephemeral
|
|
74
77
|
|
|
@@ -110,6 +113,7 @@ module Daytona
|
|
|
110
113
|
# sandbox OTel data is sent to this endpoint instead of the default collector and will not be
|
|
111
114
|
# available in the Daytona analytics API or dashboard.
|
|
112
115
|
# @param ttl_minutes [Integer, nil] Time to live in minutes (0 to disable)
|
|
116
|
+
# @param queue_timeout [Integer, nil] Minutes to wait for runner assignment before the API auto-destroys the sandbox
|
|
113
117
|
# @param ephemeral [Boolean, nil] Whether the Sandbox should be ephemeral
|
|
114
118
|
# @param spot [Boolean, nil] GPU-only. Whether the Sandbox may be instantly terminated to free GPU
|
|
115
119
|
# capacity for an on-demand GPU Sandbox
|
|
@@ -126,6 +130,7 @@ module Daytona
|
|
|
126
130
|
auto_archive_interval: nil,
|
|
127
131
|
auto_delete_interval: nil,
|
|
128
132
|
ttl_minutes: nil,
|
|
133
|
+
queue_timeout: nil,
|
|
129
134
|
volumes: nil,
|
|
130
135
|
secrets: nil,
|
|
131
136
|
network_block_all: nil,
|
|
@@ -149,6 +154,7 @@ module Daytona
|
|
|
149
154
|
@auto_archive_interval = auto_archive_interval
|
|
150
155
|
@auto_delete_interval = auto_delete_interval
|
|
151
156
|
@ttl_minutes = ttl_minutes
|
|
157
|
+
@queue_timeout = queue_timeout
|
|
152
158
|
@volumes = volumes
|
|
153
159
|
@secrets = secrets
|
|
154
160
|
@network_block_all = network_block_all
|
|
@@ -181,6 +187,7 @@ module Daytona
|
|
|
181
187
|
auto_archive_interval:,
|
|
182
188
|
auto_delete_interval:,
|
|
183
189
|
ttl_minutes:,
|
|
190
|
+
queue_timeout:,
|
|
184
191
|
volumes:,
|
|
185
192
|
secrets:,
|
|
186
193
|
network_block_all:,
|
|
@@ -238,6 +245,7 @@ module Daytona
|
|
|
238
245
|
# @param auto_archive_interval [Integer, nil] Auto-archive interval in minutes
|
|
239
246
|
# @param auto_delete_interval [Integer, nil] Auto-delete interval in minutes
|
|
240
247
|
# @param ttl_minutes [Integer, nil] Time to live in minutes (0 to disable)
|
|
248
|
+
# @param queue_timeout [Integer, nil] Minutes to wait for runner assignment before the API auto-destroys the sandbox
|
|
241
249
|
# @param volumes [Array<DaytonaApiClient::SandboxVolume>, nil] List of volumes mounts to attach to the Sandbox
|
|
242
250
|
# @param secrets [Hash<String, String>, nil] Organization Secrets to expose in the Sandbox, as a
|
|
243
251
|
# mapping of env var name to existing Secret name
|
|
@@ -289,6 +297,7 @@ module Daytona
|
|
|
289
297
|
# @param auto_archive_interval [Integer, nil] Auto-archive interval in minutes
|
|
290
298
|
# @param auto_delete_interval [Integer, nil] Auto-delete interval in minutes
|
|
291
299
|
# @param ttl_minutes [Integer, nil] Time to live in minutes (0 to disable)
|
|
300
|
+
# @param queue_timeout [Integer, nil] Minutes to wait for runner assignment before the API auto-destroys the sandbox
|
|
292
301
|
# @param volumes [Array<DaytonaApiClient::SandboxVolume>, nil] List of volumes mounts to attach to the Sandbox
|
|
293
302
|
# @param secrets [Hash<String, String>, nil] Organization Secrets to expose in the Sandbox, as a
|
|
294
303
|
# mapping of env var name to existing Secret name
|
data/lib/daytona/daytona.rb
CHANGED
|
@@ -104,7 +104,7 @@ module Daytona
|
|
|
104
104
|
# @param params [Daytona::CreateSandboxFromSnapshotParams, Daytona::CreateSandboxFromImageParams, Nil] Sandbox creation parameters
|
|
105
105
|
# @return [Daytona::Sandbox] The created sandbox
|
|
106
106
|
# @raise [Daytona::Sdk::Error] If auto_stop_interval, auto_pause_interval, auto_archive_interval, or ttl_minutes is negative,
|
|
107
|
-
# or if auto_stop_interval and auto_pause_interval are both non-zero
|
|
107
|
+
# if queue_timeout is not a positive integer, or if auto_stop_interval and auto_pause_interval are both non-zero
|
|
108
108
|
def create(params = nil, on_snapshot_create_logs: nil)
|
|
109
109
|
if params.nil?
|
|
110
110
|
params = CreateSandboxFromSnapshotParams.new(language: CodeLanguage::PYTHON)
|
|
@@ -249,7 +249,7 @@ module Daytona
|
|
|
249
249
|
# @param on_snapshot_create_logs [Proc]
|
|
250
250
|
# @return [Daytona::Sandbox] The created sandbox
|
|
251
251
|
# @raise [Daytona::Sdk::Error] If auto_stop_interval, auto_pause_interval, auto_archive_interval, or ttl_minutes is negative,
|
|
252
|
-
# or if auto_stop_interval and auto_pause_interval are both non-zero
|
|
252
|
+
# if queue_timeout is not a positive integer, or if auto_stop_interval and auto_pause_interval are both non-zero
|
|
253
253
|
def _create(params, timeout: 60, on_snapshot_create_logs: nil)
|
|
254
254
|
raise Sdk::Error, 'Timeout must be a non-negative number' if timeout.negative?
|
|
255
255
|
|
|
@@ -274,6 +274,10 @@ module Daytona
|
|
|
274
274
|
|
|
275
275
|
raise Sdk::Error, 'ttl_minutes must be a non-negative integer' if params.ttl_minutes&.negative?
|
|
276
276
|
|
|
277
|
+
unless params.queue_timeout.nil? || (params.queue_timeout.is_a?(Integer) && params.queue_timeout >= 1)
|
|
278
|
+
raise Sdk::Error, 'queue_timeout must be a positive integer'
|
|
279
|
+
end
|
|
280
|
+
|
|
277
281
|
labels = params.labels&.dup || {}
|
|
278
282
|
labels[CODE_TOOLBOX_LANGUAGE_LABEL] = params.language.to_s if params.language
|
|
279
283
|
|
|
@@ -288,6 +292,7 @@ module Daytona
|
|
|
288
292
|
auto_archive_interval: params.auto_archive_interval,
|
|
289
293
|
auto_delete_interval: params.auto_delete_interval,
|
|
290
294
|
ttl_minutes: params.ttl_minutes,
|
|
295
|
+
queue_timeout: params.queue_timeout,
|
|
291
296
|
volumes: params.volumes,
|
|
292
297
|
secrets: params.secrets&.map { |env_var, secret_name| { env_var.to_s => secret_name.to_s } },
|
|
293
298
|
network_block_all: params.network_block_all,
|
|
@@ -333,13 +338,23 @@ module Daytona
|
|
|
333
338
|
response = sandbox_api.get_sandbox(response.id)
|
|
334
339
|
end
|
|
335
340
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
341
|
+
begin
|
|
342
|
+
build_logs_response = sandbox_api.get_build_logs_url(response.id)
|
|
343
|
+
uri = URI.parse("#{build_logs_response.url}?follow=true")
|
|
344
|
+
|
|
345
|
+
headers = {}
|
|
346
|
+
sandbox_api.api_client.update_params_for_auth!(headers, nil, ['bearer'])
|
|
347
|
+
Util.stream_async(uri:, headers:, on_chunk: on_snapshot_create_logs)
|
|
348
|
+
rescue StandardError => e
|
|
349
|
+
refreshed = begin
|
|
350
|
+
sandbox_api.get_sandbox(response.id)
|
|
351
|
+
rescue StandardError
|
|
352
|
+
raise e
|
|
353
|
+
end
|
|
354
|
+
raise e unless destroyed_by_lifecycle?(refreshed)
|
|
339
355
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
Util.stream_async(uri:, headers:, on_chunk: on_snapshot_create_logs)
|
|
356
|
+
response = refreshed
|
|
357
|
+
end
|
|
343
358
|
end
|
|
344
359
|
|
|
345
360
|
sandbox = to_sandbox(sandbox_dto: response)
|
|
@@ -395,6 +410,15 @@ module Daytona
|
|
|
395
410
|
|
|
396
411
|
# @param sandbox_dto [DaytonaApiClient::Sandbox, DaytonaApiClient::SandboxListItem]
|
|
397
412
|
# @return [Daytona::Sandbox]
|
|
413
|
+
def destroyed_by_lifecycle?(sandbox_dto)
|
|
414
|
+
if sandbox_dto.state == DaytonaApiClient::SandboxState::DESTROYED &&
|
|
415
|
+
(sandbox_dto.queue_timed_out_at || sandbox_dto.spot_evicted_at)
|
|
416
|
+
true
|
|
417
|
+
else
|
|
418
|
+
false
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
398
422
|
def to_sandbox(sandbox_dto:)
|
|
399
423
|
Sandbox.new(
|
|
400
424
|
sandbox_dto:,
|
data/lib/daytona/sandbox.rb
CHANGED
|
@@ -116,6 +116,9 @@ module Daytona
|
|
|
116
116
|
# @return [String, nil] When the sandbox was evicted by spot preemption
|
|
117
117
|
attr_reader :spot_evicted_at
|
|
118
118
|
|
|
119
|
+
# @return [String, nil] When the sandbox timed out waiting in the queue for a runner
|
|
120
|
+
attr_reader :queue_timed_out_at
|
|
121
|
+
|
|
119
122
|
# @return [String, nil] The GPU type assigned to the sandbox
|
|
120
123
|
attr_reader :gpu_type
|
|
121
124
|
|
|
@@ -166,6 +169,9 @@ module Daytona
|
|
|
166
169
|
# @return [String, nil] When the sandbox will be automatically destroyed (nil if no TTL is set)
|
|
167
170
|
attr_reader :auto_destroy_at
|
|
168
171
|
|
|
172
|
+
# @return [Integer, nil] Minutes the sandbox may wait for runner assignment before the API auto-destroys it
|
|
173
|
+
attr_reader :queue_timeout
|
|
174
|
+
|
|
169
175
|
# @return [String] The creation timestamp of the sandbox
|
|
170
176
|
attr_reader :created_at
|
|
171
177
|
|
|
@@ -1111,6 +1117,7 @@ module Daytona
|
|
|
1111
1117
|
@gpu = sandbox_dto.gpu
|
|
1112
1118
|
@spot = sandbox_dto.spot || false
|
|
1113
1119
|
@spot_evicted_at = sandbox_dto.spot_evicted_at
|
|
1120
|
+
@queue_timed_out_at = sandbox_dto.queue_timed_out_at
|
|
1114
1121
|
@gpu_type = sandbox_dto.gpu_type
|
|
1115
1122
|
@memory = sandbox_dto.memory
|
|
1116
1123
|
@disk = sandbox_dto.disk
|
|
@@ -1122,6 +1129,7 @@ module Daytona
|
|
|
1122
1129
|
@auto_archive_interval = sandbox_dto.auto_archive_interval
|
|
1123
1130
|
@auto_delete_interval = sandbox_dto.auto_delete_interval
|
|
1124
1131
|
@auto_destroy_at = sandbox_dto.auto_destroy_at
|
|
1132
|
+
@queue_timeout = sandbox_dto.queue_timeout
|
|
1125
1133
|
@created_at = sandbox_dto.created_at
|
|
1126
1134
|
@updated_at = sandbox_dto.updated_at
|
|
1127
1135
|
@last_activity_at = sandbox_dto.last_activity_at
|
|
@@ -1245,6 +1253,7 @@ module Daytona
|
|
|
1245
1253
|
first_poll = false
|
|
1246
1254
|
|
|
1247
1255
|
safe_refresh ? refresh_data_safe : refresh
|
|
1256
|
+
raise_destroyed_lifecycle_error_if_needed(target_strings)
|
|
1248
1257
|
|
|
1249
1258
|
mutex.synchronize do
|
|
1250
1259
|
next if result_state
|
|
@@ -1270,6 +1279,8 @@ module Daytona
|
|
|
1270
1279
|
rescue StandardError
|
|
1271
1280
|
raise e
|
|
1272
1281
|
end
|
|
1282
|
+
|
|
1283
|
+
raise_destroyed_lifecycle_error_if_needed(target_strings)
|
|
1273
1284
|
current = state.to_s
|
|
1274
1285
|
return if target_strings.include?(current)
|
|
1275
1286
|
|
|
@@ -1293,6 +1304,26 @@ module Daytona
|
|
|
1293
1304
|
rescue StandardError # rubocop:disable Lint/SuppressedException
|
|
1294
1305
|
end
|
|
1295
1306
|
|
|
1307
|
+
def raise_destroyed_lifecycle_error_if_needed(target_strings)
|
|
1308
|
+
return unless state.to_s == DaytonaApiClient::SandboxState::DESTROYED.to_s
|
|
1309
|
+
return if target_strings.include?(DaytonaApiClient::SandboxState::DESTROYED.to_s)
|
|
1310
|
+
|
|
1311
|
+
raise Sdk::QueueTimeoutError, queue_timeout_message if queue_timed_out_at
|
|
1312
|
+
return unless spot_evicted_at
|
|
1313
|
+
|
|
1314
|
+
raise Sdk::SpotEvictedError,
|
|
1315
|
+
"Sandbox #{id} was evicted by spot preemption at #{spot_evicted_at}"
|
|
1316
|
+
end
|
|
1317
|
+
|
|
1318
|
+
def queue_timeout_message
|
|
1319
|
+
waited = if queue_timeout.nil?
|
|
1320
|
+
''
|
|
1321
|
+
else
|
|
1322
|
+
" #{queue_timeout} #{queue_timeout == 1 ? 'minute' : 'minutes'}"
|
|
1323
|
+
end
|
|
1324
|
+
"Sandbox #{id} was destroyed after waiting#{waited} for a runner (queue timed out at #{queue_timed_out_at})"
|
|
1325
|
+
end
|
|
1326
|
+
|
|
1296
1327
|
def ensure_subscribed
|
|
1297
1328
|
@waiter_mutex.synchronize do
|
|
1298
1329
|
return unless @subscription_manager
|
data/lib/daytona/sdk/errors.rb
CHANGED
|
@@ -107,6 +107,17 @@ module Daytona
|
|
|
107
107
|
# catch the broader connection-failure category also match.
|
|
108
108
|
class ConnectionTimeoutError < ConnectionError; end
|
|
109
109
|
|
|
110
|
+
# ---------------------------------------------------------------------
|
|
111
|
+
# SDK-detected sandbox lifecycle
|
|
112
|
+
# ---------------------------------------------------------------------
|
|
113
|
+
|
|
114
|
+
# Raised when a Sandbox was destroyed by the API because it waited longer
|
|
115
|
+
# than its queue timeout for a runner.
|
|
116
|
+
class QueueTimeoutError < TimeoutError; end
|
|
117
|
+
|
|
118
|
+
# Raised when a Sandbox was destroyed by spot preemption.
|
|
119
|
+
class SpotEvictedError < Error; end
|
|
120
|
+
|
|
110
121
|
# ---------------------------------------------------------------------
|
|
111
122
|
# Domain subclasses — each inherits from the HTTP-status parent that
|
|
112
123
|
# matches its server-side status code.
|
data/lib/daytona/sdk/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: daytona
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.220.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daytona Platforms Inc.
|
|
@@ -91,42 +91,42 @@ dependencies:
|
|
|
91
91
|
requirements:
|
|
92
92
|
- - '='
|
|
93
93
|
- !ruby/object:Gem::Version
|
|
94
|
-
version: 0.
|
|
94
|
+
version: 0.220.0
|
|
95
95
|
type: :runtime
|
|
96
96
|
prerelease: false
|
|
97
97
|
version_requirements: !ruby/object:Gem::Requirement
|
|
98
98
|
requirements:
|
|
99
99
|
- - '='
|
|
100
100
|
- !ruby/object:Gem::Version
|
|
101
|
-
version: 0.
|
|
101
|
+
version: 0.220.0
|
|
102
102
|
- !ruby/object:Gem::Dependency
|
|
103
103
|
name: daytona_api_client
|
|
104
104
|
requirement: !ruby/object:Gem::Requirement
|
|
105
105
|
requirements:
|
|
106
106
|
- - '='
|
|
107
107
|
- !ruby/object:Gem::Version
|
|
108
|
-
version: 0.
|
|
108
|
+
version: 0.220.0
|
|
109
109
|
type: :runtime
|
|
110
110
|
prerelease: false
|
|
111
111
|
version_requirements: !ruby/object:Gem::Requirement
|
|
112
112
|
requirements:
|
|
113
113
|
- - '='
|
|
114
114
|
- !ruby/object:Gem::Version
|
|
115
|
-
version: 0.
|
|
115
|
+
version: 0.220.0
|
|
116
116
|
- !ruby/object:Gem::Dependency
|
|
117
117
|
name: daytona_toolbox_api_client
|
|
118
118
|
requirement: !ruby/object:Gem::Requirement
|
|
119
119
|
requirements:
|
|
120
120
|
- - '='
|
|
121
121
|
- !ruby/object:Gem::Version
|
|
122
|
-
version: 0.
|
|
122
|
+
version: 0.220.0
|
|
123
123
|
type: :runtime
|
|
124
124
|
prerelease: false
|
|
125
125
|
version_requirements: !ruby/object:Gem::Requirement
|
|
126
126
|
requirements:
|
|
127
127
|
- - '='
|
|
128
128
|
- !ruby/object:Gem::Version
|
|
129
|
-
version: 0.
|
|
129
|
+
version: 0.220.0
|
|
130
130
|
- !ruby/object:Gem::Dependency
|
|
131
131
|
name: dotenv
|
|
132
132
|
requirement: !ruby/object:Gem::Requirement
|