volcano-sdk 0.27.0 → 0.28.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/volcano/function_resolution.rb +18 -15
- data/lib/volcano/function_response.rb +8 -7
- data/lib/volcano/functions.rb +1 -1
- data/lib/volcano/lock_guard.rb +6 -2
- data/lib/volcano/lock_renewer.rb +3 -2
- data/lib/volcano/lock_session.rb +1 -0
- data/lib/volcano/log_responses.rb +11 -7
- data/lib/volcano/realtime/blocking_call.rb +8 -9
- data/lib/volcano/realtime/protocol_recovery_position.rb +10 -5
- data/lib/volcano/sign_up_result.rb +6 -1
- data/lib/volcano/version.rb +1 -1
- data/sig/lock_guard.rbs +21 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 47568709329b06a2dd8a84c4ab0058accc47d749d6cc773de6a87c0fc08a6ce1
|
|
4
|
+
data.tar.gz: d9685709f29037f6db0c5598bae32a84537500f2025337dbf6497a729a315774
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 776a324b0d6330c0152e4ef6f46f87d4145f5605c8ed9c4f1fbe648418b8d806e67c668af5f1d41e75ecd5825aa58b4b8d894cb6941c75413f3991153e021f84
|
|
7
|
+
data.tar.gz: 2b3a2bc60a3cd4e77c32c08f44fc2c8529cc886688381eec5abcdb8ca6bd4f2160fa8bddbfba75544fd865b99b44160a055fece6b65f78c4c6ca1fd79a8bddaf
|
|
@@ -16,11 +16,7 @@ module Volcano
|
|
|
16
16
|
# A cached resolve result. A nil resolution is a remembered miss.
|
|
17
17
|
Outcome = Data.define(:resolution, :failure)
|
|
18
18
|
|
|
19
|
-
Failure = Data.define(:message, :code, :retry_after)
|
|
20
|
-
def exception
|
|
21
|
-
Error::NotFoundError.new(message.dup, status: 404, code: code&.dup, retry_after: retry_after)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
19
|
+
Failure = Data.define(:message, :code, :retry_after)
|
|
24
20
|
private_constant :Failure
|
|
25
21
|
|
|
26
22
|
Entry = Data.define(:outcome, :expires_at)
|
|
@@ -51,21 +47,23 @@ module Volcano
|
|
|
51
47
|
# when the API itself is plaintext, so a resolve response cannot
|
|
52
48
|
# downgrade a credential that is otherwise protected in transit.
|
|
53
49
|
def valid_invoke_url(value, api_url)
|
|
54
|
-
|
|
50
|
+
url = nonempty_url(value)
|
|
51
|
+
return nil unless url
|
|
55
52
|
|
|
56
|
-
uri = URI.parse(
|
|
53
|
+
uri = URI.parse(url)
|
|
57
54
|
return nil unless usable_address?(uri)
|
|
58
55
|
|
|
59
|
-
usable_scheme?(uri.scheme, api_url) ?
|
|
56
|
+
usable_scheme?(uri.scheme, api_url) ? url : nil
|
|
60
57
|
rescue URI::InvalidURIError
|
|
61
58
|
nil
|
|
62
59
|
end
|
|
63
60
|
|
|
64
61
|
# Returns the cached Outcome for a name, or nil when it must be resolved.
|
|
65
62
|
def lookup(api_url, authorization, name)
|
|
63
|
+
# @type var key: [String, String, String]
|
|
66
64
|
key = [api_url, authorization, name]
|
|
67
65
|
@lock.synchronize do
|
|
68
|
-
entry = @entries
|
|
66
|
+
entry = @entries.fetch(key, nil)
|
|
69
67
|
next nil if entry.nil?
|
|
70
68
|
|
|
71
69
|
if entry.expires_at <= now
|
|
@@ -89,6 +87,11 @@ module Volcano
|
|
|
89
87
|
write([api_url, authorization, name], Outcome.new(resolution: nil, failure: failure), NEGATIVE_TTL_SECONDS)
|
|
90
88
|
end
|
|
91
89
|
|
|
90
|
+
def error_for(failure)
|
|
91
|
+
Error::NotFoundError.new(failure.message.dup, status: 404, code: failure.code&.dup,
|
|
92
|
+
retry_after: failure.retry_after)
|
|
93
|
+
end
|
|
94
|
+
|
|
92
95
|
# Drops one cached resolution that turned out to be stale.
|
|
93
96
|
def forget(api_url, authorization, name)
|
|
94
97
|
@lock.synchronize { @entries.delete([api_url, authorization, name]) }
|
|
@@ -106,8 +109,8 @@ module Volcano
|
|
|
106
109
|
|
|
107
110
|
private
|
|
108
111
|
|
|
109
|
-
def nonempty_url
|
|
110
|
-
value.is_a?(String) && !value.empty?
|
|
112
|
+
def nonempty_url(value)
|
|
113
|
+
value if value.is_a?(String) && !value.empty?
|
|
111
114
|
end
|
|
112
115
|
|
|
113
116
|
def usable_address?(uri)
|
|
@@ -126,15 +129,15 @@ module Volcano
|
|
|
126
129
|
def write(key, outcome, ttl_seconds)
|
|
127
130
|
@lock.synchronize do
|
|
128
131
|
@entries[key] = Entry.new(outcome: outcome, expires_at: now + ttl_seconds)
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
evict_expired_entries
|
|
132
|
+
evict_expired_entries if @entries.size > MAX_ENTRIES
|
|
132
133
|
end
|
|
133
134
|
end
|
|
134
135
|
|
|
135
136
|
def evict_expired_entries
|
|
136
137
|
@entries.delete_if { |_, entry| entry.expires_at <= now }
|
|
137
|
-
|
|
138
|
+
while @entries.size > MAX_ENTRIES
|
|
139
|
+
@entries.min_by(1) { |_, entry| entry.expires_at }.each { |pair| @entries.delete(pair.first) }
|
|
140
|
+
end
|
|
138
141
|
end
|
|
139
142
|
end
|
|
140
143
|
end
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
module Volcano
|
|
4
4
|
# Immutable result of one function invocation.
|
|
5
|
-
FunctionResponse = Data.define(:data, :status, :headers, :version)
|
|
5
|
+
FunctionResponse = Data.define(:data, :status, :headers, :version)
|
|
6
|
+
|
|
7
|
+
# Reopen the generated Data class so Steep can check its initializer.
|
|
8
|
+
class FunctionResponse
|
|
6
9
|
def initialize(data:, status:, headers:, version:)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
version: version&.dup&.freeze
|
|
12
|
-
)
|
|
10
|
+
data = immutable_json(data)
|
|
11
|
+
headers = immutable_json(headers)
|
|
12
|
+
version = version&.dup&.freeze
|
|
13
|
+
super
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
private
|
data/lib/volcano/functions.rb
CHANGED
data/lib/volcano/lock_guard.rb
CHANGED
|
@@ -84,7 +84,7 @@ module Volcano
|
|
|
84
84
|
wait = wait_duration(deadline)
|
|
85
85
|
return false unless wait
|
|
86
86
|
|
|
87
|
-
@changed.wait(@mutex, wait)
|
|
87
|
+
@changed.wait(@mutex, Float(wait))
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
90
|
|
|
@@ -129,7 +129,11 @@ module Volcano
|
|
|
129
129
|
def remaining_time = @lease_clock.remaining
|
|
130
130
|
|
|
131
131
|
def wait_deadline(timeout)
|
|
132
|
-
|
|
132
|
+
return unless timeout
|
|
133
|
+
|
|
134
|
+
raise ArgumentError, 'invalid timeout' unless timeout.is_a?(Numeric) && timeout.real? && timeout.finite?
|
|
135
|
+
|
|
136
|
+
@lease_clock.monotonic_now + timeout
|
|
133
137
|
end
|
|
134
138
|
end
|
|
135
139
|
end
|
data/lib/volcano/lock_renewer.rb
CHANGED
|
@@ -22,10 +22,11 @@ module Volcano
|
|
|
22
22
|
|
|
23
23
|
def stop
|
|
24
24
|
request_stop
|
|
25
|
-
|
|
25
|
+
thread = @thread
|
|
26
|
+
return unless thread
|
|
26
27
|
|
|
27
28
|
# Renew requires current token ownership, so a late request cannot resurrect a released lease.
|
|
28
|
-
|
|
29
|
+
thread.join(@config.shutdown_timeout)
|
|
29
30
|
end
|
|
30
31
|
|
|
31
32
|
private
|
data/lib/volcano/lock_session.rb
CHANGED
|
@@ -20,24 +20,28 @@ module Volcano
|
|
|
20
20
|
end
|
|
21
21
|
private_constant :ImmutableLogJSON
|
|
22
22
|
|
|
23
|
+
LogSearchResponse = Data.define(:data, :limit, :has_more, :next_cursor)
|
|
24
|
+
|
|
23
25
|
# Immutable page returned by a project log search.
|
|
24
|
-
LogSearchResponse
|
|
26
|
+
class LogSearchResponse
|
|
25
27
|
include ImmutableLogJSON
|
|
26
28
|
|
|
27
29
|
def initialize(data:, limit:, has_more:, next_cursor: nil)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
)
|
|
30
|
+
data = immutable_json(data)
|
|
31
|
+
next_cursor = next_cursor&.dup&.freeze
|
|
32
|
+
super
|
|
32
33
|
end
|
|
33
34
|
end
|
|
34
35
|
|
|
36
|
+
LogActivityResponse = Data.define(:data, :total)
|
|
37
|
+
|
|
35
38
|
# Immutable bucketed project log activity.
|
|
36
|
-
LogActivityResponse
|
|
39
|
+
class LogActivityResponse
|
|
37
40
|
include ImmutableLogJSON
|
|
38
41
|
|
|
39
42
|
def initialize(data:, total:)
|
|
40
|
-
|
|
43
|
+
data = immutable_json(data)
|
|
44
|
+
super
|
|
41
45
|
end
|
|
42
46
|
end
|
|
43
47
|
end
|
|
@@ -4,26 +4,25 @@ module Volcano
|
|
|
4
4
|
class Realtime
|
|
5
5
|
# Runs one blocking operation off the Async reactor and returns its result.
|
|
6
6
|
module BlockingCall
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
Success = Data.define(:value)
|
|
8
|
+
Failure = Data.define(:error)
|
|
9
|
+
private_constant :Success, :Failure
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def call(&operation)
|
|
11
|
+
def self.call(&operation)
|
|
13
12
|
results = ::Queue.new
|
|
14
13
|
worker = Thread.new { execute(results, operation) }
|
|
15
14
|
worker.report_on_exception = false
|
|
16
15
|
result = results.pop
|
|
17
16
|
worker.join
|
|
18
|
-
raise result.error if result.
|
|
17
|
+
raise result.error if result.is_a?(Failure)
|
|
19
18
|
|
|
20
19
|
result.value
|
|
21
20
|
end
|
|
22
21
|
|
|
23
|
-
def execute(results, operation)
|
|
24
|
-
results <<
|
|
22
|
+
def self.execute(results, operation)
|
|
23
|
+
results << Success.new(value: operation.call)
|
|
25
24
|
rescue StandardError => e
|
|
26
|
-
results <<
|
|
25
|
+
results << Failure.new(error: e)
|
|
27
26
|
end
|
|
28
27
|
private_class_method :execute
|
|
29
28
|
end
|
|
@@ -21,7 +21,7 @@ module Volcano
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def complete_publication(channel, publication)
|
|
24
|
-
current = @stream_positions
|
|
24
|
+
current = @stream_positions.fetch(channel, nil)
|
|
25
25
|
return unless current
|
|
26
26
|
|
|
27
27
|
completed = publication_position(publication, current)
|
|
@@ -49,7 +49,7 @@ module Volcano
|
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def mark_publication_gap(channel, publication)
|
|
52
|
-
current = @stream_positions
|
|
52
|
+
current = @stream_positions.fetch(channel, nil)
|
|
53
53
|
return unless current
|
|
54
54
|
|
|
55
55
|
gap = publication_position(publication, current)
|
|
@@ -68,7 +68,7 @@ module Volcano
|
|
|
68
68
|
def store_earliest_gap(channel, gap)
|
|
69
69
|
existing = @position_gaps[channel]
|
|
70
70
|
return if existing == true
|
|
71
|
-
return if existing && existing.fetch(:offset) <= gap.fetch(:offset)
|
|
71
|
+
return if existing.is_a?(Hash) && existing.fetch(:offset) <= gap.fetch(:offset)
|
|
72
72
|
|
|
73
73
|
@position_gaps[channel] = gap
|
|
74
74
|
end
|
|
@@ -84,7 +84,9 @@ module Volcano
|
|
|
84
84
|
return unless epoch.is_a?(String) && !epoch.empty?
|
|
85
85
|
return unless offset.is_a?(Integer) && offset >= 0
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
# @type var position: position
|
|
88
|
+
position = { epoch: epoch.dup.freeze, offset: offset.freeze }
|
|
89
|
+
position.freeze
|
|
88
90
|
end
|
|
89
91
|
|
|
90
92
|
def same_epoch?(first, second) = first.fetch(:epoch) == second.fetch(:epoch)
|
|
@@ -95,7 +97,10 @@ module Volcano
|
|
|
95
97
|
|
|
96
98
|
def completion_before_gap?(channel, completed)
|
|
97
99
|
gap = @position_gaps[channel]
|
|
98
|
-
|
|
100
|
+
return false if gap == true
|
|
101
|
+
return true unless gap.is_a?(Hash)
|
|
102
|
+
|
|
103
|
+
completed.fetch(:offset) < gap.fetch(:offset)
|
|
99
104
|
end
|
|
100
105
|
|
|
101
106
|
def mark_unknown_gap(channel) = @position_gaps[channel] = true
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Volcano
|
|
4
|
-
SignUpResult = Data.define(:confirmation_required, :message, :session)
|
|
4
|
+
SignUpResult = Data.define(:confirmation_required, :message, :session)
|
|
5
|
+
|
|
6
|
+
# Reopen the generated Data class so Steep can check its initializer.
|
|
7
|
+
class SignUpResult
|
|
8
|
+
# @dynamic confirmation_required, message, session, members, with, to_h, deconstruct, deconstruct_keys
|
|
9
|
+
# @dynamic self.[], self.members
|
|
5
10
|
def initialize(confirmation_required:, message:, session: nil)
|
|
6
11
|
super
|
|
7
12
|
end
|
data/lib/volcano/version.rb
CHANGED
data/sig/lock_guard.rbs
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Volcano
|
|
2
|
+
interface _LeaseStartedAt
|
|
3
|
+
def monotonic: () -> Float
|
|
4
|
+
def wall: () -> Time
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
class LockGuard
|
|
8
|
+
EXPIRY_MESSAGE: String
|
|
9
|
+
MAX_EXPIRY_POLL_SECONDS: Float
|
|
10
|
+
UNSAFE_RENEWAL_MESSAGE: String
|
|
11
|
+
|
|
12
|
+
attr_reader ttl: Integer
|
|
13
|
+
|
|
14
|
+
def initialize: (LockLease lease, ttl: Integer, started_at: _LeaseStartedAt) -> void
|
|
15
|
+
def lease: () -> LockLease
|
|
16
|
+
def lost?: () -> bool
|
|
17
|
+
# The timeout must be a finite real number.
|
|
18
|
+
def wait_lost: (?timeout: Numeric?) -> bool
|
|
19
|
+
def failure: () -> StandardError?
|
|
20
|
+
end
|
|
21
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: volcano-sdk
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.28.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kong
|
|
@@ -609,6 +609,7 @@ files:
|
|
|
609
609
|
- sig/email_change_result.rbs
|
|
610
610
|
- sig/errors.rbs
|
|
611
611
|
- sig/function_response.rbs
|
|
612
|
+
- sig/lock_guard.rbs
|
|
612
613
|
- sig/lock_records.rbs
|
|
613
614
|
- sig/log_responses.rbs
|
|
614
615
|
- sig/oauth_records.rbs
|