cuboid 0.4 → 0.5
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/cuboid/rest/server/instance_helpers.rb +3 -20
- data/lib/cuboid/rest/server/routes/instances.rb +7 -10
- data/lib/cuboid/rpc/server/instance.rb +54 -66
- data/lib/version +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 28dd253a7fd5dc33e5f8d62a9ae2fae905a46a786bb21d57cb8c47f9792ba821
|
|
4
|
+
data.tar.gz: 319fcbba6a3a5ed6b41eec3dbcde53c7e4f7d43c658df4657e660339e2198933
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 859207bc319b54b3eaff619dcdc1aa770e7136fe30cea8dcc86556595a204711190c0a463398038ee30a5ce8a9be25eea3637fc79676daa150b045f8b4ab880e
|
|
7
|
+
data.tar.gz: 64c5901b28b942d2771dca8ec22af4ad893a8d11c53acf1d094a7c65882c9199105d18b5bbc8872b094a1447896d07897b1bf1db8b85e808a569a2ae92e19cbc
|
|
@@ -5,9 +5,8 @@ module Rest
|
|
|
5
5
|
class Server
|
|
6
6
|
|
|
7
7
|
# Sinatra-coupled supplement to `Cuboid::Server::InstanceHelpers` —
|
|
8
|
-
# the methods that read `env
|
|
9
|
-
# defined on `Rest::Server`)
|
|
10
|
-
# scheduler-removed instances. Everything that doesn't need Sinatra
|
|
8
|
+
# the methods that read `env` or call `handle_error` (a Sinatra helper
|
|
9
|
+
# defined on `Rest::Server`). Everything that doesn't need Sinatra
|
|
11
10
|
# stays on the shared module above.
|
|
12
11
|
module InstanceHelpers
|
|
13
12
|
|
|
@@ -19,24 +18,8 @@ module InstanceHelpers
|
|
|
19
18
|
super
|
|
20
19
|
end
|
|
21
20
|
|
|
22
|
-
# Adds Sinatra-session cleanup for IDs the scheduler has dropped.
|
|
23
|
-
# The shared `update_from_scheduler` already removes them from the
|
|
24
|
-
# instance map; this override prunes the matching session keys so a
|
|
25
|
-
# second request from the same browser doesn't try to reach a dead
|
|
26
|
-
# instance.
|
|
27
|
-
def update_from_scheduler
|
|
28
|
-
return if !scheduler
|
|
29
|
-
|
|
30
|
-
pruned = scheduler.failed.keys | scheduler.completed.keys
|
|
31
|
-
super
|
|
32
|
-
pruned.each { |id| session.delete id }
|
|
33
|
-
end
|
|
34
|
-
|
|
35
21
|
def instance_for( id, &block )
|
|
36
|
-
cleanup = proc
|
|
37
|
-
instances.delete( id ).close
|
|
38
|
-
session.delete id
|
|
39
|
-
end
|
|
22
|
+
cleanup = proc { instances.delete( id ).close }
|
|
40
23
|
|
|
41
24
|
handle_error cleanup do
|
|
42
25
|
block.call instances[id]
|
|
@@ -36,20 +36,19 @@ module Instances
|
|
|
36
36
|
app.get '/instances/:instance' do
|
|
37
37
|
ensure_instance!
|
|
38
38
|
|
|
39
|
-
session
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
# The Sinatra session is per-cookie, but its id isn't
|
|
40
|
+
# exposed; lazy-init a per-client UUID and pass it as
|
|
41
|
+
# the RPC `session:` token so the engine tracks the
|
|
42
|
+
# error-line offset server-side.
|
|
43
|
+
require 'securerandom' unless defined?( SecureRandom )
|
|
44
|
+
session[:rpc_session_id] ||= SecureRandom.uuid
|
|
42
45
|
|
|
43
46
|
data = instance_for( params[:instance] ) do |instance|
|
|
44
47
|
instance.progress(
|
|
45
|
-
|
|
46
|
-
errors: session[params[:instance]][:seen_errors],
|
|
47
|
-
]
|
|
48
|
+
session: "#{session[:rpc_session_id]}:#{params[:instance]}"
|
|
48
49
|
)
|
|
49
50
|
end
|
|
50
51
|
|
|
51
|
-
session[params[:instance]][:seen_errors] += data[:errors].size
|
|
52
|
-
|
|
53
52
|
json data
|
|
54
53
|
end
|
|
55
54
|
|
|
@@ -114,8 +113,6 @@ module Instances
|
|
|
114
113
|
|
|
115
114
|
instances.delete( id ).close
|
|
116
115
|
|
|
117
|
-
session.delete params[:instance]
|
|
118
|
-
|
|
119
116
|
json nil
|
|
120
117
|
end
|
|
121
118
|
|
|
@@ -152,51 +152,38 @@ class Instance
|
|
|
152
152
|
# In addition, ask to **not** be served data you already have, like
|
|
153
153
|
# error messages.
|
|
154
154
|
#
|
|
155
|
-
#
|
|
156
|
-
#
|
|
157
|
-
#
|
|
158
|
-
# the
|
|
155
|
+
# Pass a `session:` token (any caller-chosen string) and the
|
|
156
|
+
# server returns only error lines past the previous offset
|
|
157
|
+
# under that token. Reuse the same token across polls for
|
|
158
|
+
# the same logical view; pick a fresh one to start fresh.
|
|
159
159
|
#
|
|
160
|
-
#
|
|
161
|
-
#
|
|
162
|
-
# This is done by telling the method how many error messages you already
|
|
163
|
-
# have and you will be served the errors from the error-log that are past
|
|
164
|
-
# that line.
|
|
165
|
-
# So, if you were to use a loop to get fresh progress data it would look
|
|
166
|
-
# like so:
|
|
167
|
-
#
|
|
168
|
-
# error_cnt = 0
|
|
169
|
-
# i = 0
|
|
160
|
+
# token = SecureRandom.uuid
|
|
170
161
|
# while sleep 1
|
|
171
|
-
#
|
|
172
|
-
#
|
|
173
|
-
#
|
|
174
|
-
# # Only request errors we don't already have
|
|
175
|
-
# errors = instance.progress( with: { errors: error_cnt } )[:errors]
|
|
176
|
-
# error_cnt += errors.size
|
|
177
|
-
#
|
|
178
|
-
# # You will only see new errors
|
|
179
|
-
# puts errors.join("\n")
|
|
162
|
+
# errors = instance.progress( session: token )[:errors]
|
|
163
|
+
# puts errors.join( "\n" )
|
|
180
164
|
# end
|
|
181
165
|
#
|
|
182
|
-
#
|
|
183
|
-
#
|
|
184
|
-
# @option options [Array<Symbol, Hash>] :with
|
|
185
|
-
# Specify data to include:
|
|
186
|
-
#
|
|
187
|
-
# * :errors -- Errors and the line offset to use for {#errors}.
|
|
188
|
-
# Pass as a hash, like: `{ errors: 10 }`
|
|
189
|
-
# @option options [Array<Symbol, Hash>] :without
|
|
190
|
-
# Specify data to exclude:
|
|
166
|
+
# Without `session`, callers must opt into errors via
|
|
167
|
+
# `with: [:errors]` and will receive the full set every poll.
|
|
191
168
|
#
|
|
192
|
-
#
|
|
169
|
+
# @param [Hash] options
|
|
170
|
+
# @option options [String, Symbol] :session
|
|
171
|
+
# Caller-chosen session token. When provided, the response
|
|
172
|
+
# carries only errors past the previously emitted offset.
|
|
173
|
+
# @option options [Array<Symbol>] :with
|
|
174
|
+
# Block names to include when no session is in use. Currently
|
|
175
|
+
# only `:errors` is delta-able.
|
|
176
|
+
# @option options [Array<Symbol>] :without
|
|
177
|
+
# Block names to exclude. One or more of `:statistics`,
|
|
178
|
+
# `:errors`. Takes precedence over `with:` and over the
|
|
179
|
+
# session-on-by-default blocks.
|
|
193
180
|
#
|
|
194
181
|
# @return [Hash]
|
|
195
182
|
# * `statistics` -- General runtime statistics (merged when part of Grid)
|
|
196
183
|
# (enabled by default)
|
|
197
184
|
# * `status` -- {#status}
|
|
198
185
|
# * `busy` -- {#busy?}
|
|
199
|
-
# * `errors` -- {#errors}
|
|
186
|
+
# * `errors` -- {#errors}
|
|
200
187
|
def progress( options = {} )
|
|
201
188
|
progress_handler( options.merge( as_hash: true ) )
|
|
202
189
|
end
|
|
@@ -294,49 +281,50 @@ class Instance
|
|
|
294
281
|
[Process.pid]
|
|
295
282
|
end
|
|
296
283
|
|
|
297
|
-
def self.
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
case w
|
|
301
|
-
when Array
|
|
302
|
-
w.compact.flatten.each do |q|
|
|
303
|
-
case q
|
|
304
|
-
when String, Symbol
|
|
305
|
-
parsed[q.to_sym] = nil
|
|
306
|
-
|
|
307
|
-
when Hash
|
|
308
|
-
parsed.merge!( q.my_symbolize_keys )
|
|
309
|
-
end
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
when String, Symbol
|
|
313
|
-
parsed[w.to_sym] = nil
|
|
314
|
-
|
|
315
|
-
when Hash
|
|
316
|
-
parsed.merge!( w.my_symbolize_keys )
|
|
317
|
-
end
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
parsed
|
|
284
|
+
def self.parse_block_names( raw )
|
|
285
|
+
return [] if raw.nil?
|
|
286
|
+
Array( raw ).flatten.compact.map(&:to_sym)
|
|
321
287
|
end
|
|
322
288
|
|
|
323
289
|
private
|
|
324
290
|
|
|
291
|
+
# Server-side state for `session:`-tracked progress polls.
|
|
292
|
+
# Keyed off a caller-supplied token so RPC clients don't have
|
|
293
|
+
# to re-transmit the error line offset on every poll.
|
|
294
|
+
def progress_sessions
|
|
295
|
+
@progress_sessions ||= {}
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def progress_session_for( id )
|
|
299
|
+
progress_sessions[id] ||= { seen_errors: 0 }
|
|
300
|
+
end
|
|
301
|
+
|
|
325
302
|
def progress_handler( options = {}, &block )
|
|
326
|
-
|
|
327
|
-
|
|
303
|
+
options = options.my_symbolize_keys
|
|
304
|
+
|
|
305
|
+
session_id = options.delete( :session )
|
|
306
|
+
session = progress_session_for( session_id ) if session_id
|
|
307
|
+
|
|
308
|
+
with = self.class.parse_block_names( options[:with] )
|
|
309
|
+
without = self.class.parse_block_names( options[:without] )
|
|
310
|
+
|
|
311
|
+
# Under a session, errors are on by default; without a
|
|
312
|
+
# session, callers opt in via `with: [:errors]`.
|
|
313
|
+
include_errors = !without.include?( :errors ) && (session || with.include?( :errors ))
|
|
328
314
|
|
|
329
|
-
|
|
315
|
+
wrapper_options = {
|
|
330
316
|
as_hash: options[:as_hash],
|
|
331
317
|
statistics: !without.include?( :statistics )
|
|
332
318
|
}
|
|
319
|
+
wrapper_options[:errors] = session ? session[:seen_errors] : 0 if include_errors
|
|
333
320
|
|
|
334
|
-
|
|
335
|
-
options[:errors] = with[:errors]
|
|
336
|
-
end
|
|
337
|
-
|
|
338
|
-
@application.progress( options ) do |data|
|
|
321
|
+
@application.progress( wrapper_options ) do |data|
|
|
339
322
|
data[:busy] = busy?
|
|
323
|
+
|
|
324
|
+
if session && data[:errors]
|
|
325
|
+
session[:seen_errors] += data[:errors].size
|
|
326
|
+
end
|
|
327
|
+
|
|
340
328
|
block.call( data )
|
|
341
329
|
end
|
|
342
330
|
end
|
data/lib/version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.5
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cuboid
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '0.
|
|
4
|
+
version: '0.5'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tasos Laskos
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: awesome_print
|