statelydb 0.14.0 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/common/auth/auth_token_provider.rb +12 -4
- data/lib/common/auth/token_fetcher.rb +45 -5
- data/sig/statelydb.rbi +33 -6
- data/sig/statelydb.rbs +23 -3
- 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: f1d7563d7f40d84bdc1ef3dacff41707ed1d915b638223d33b488ca4c7de531f
|
4
|
+
data.tar.gz: dd682b92fbc100505e15820c5415acadc9defc6bc2f2d0dad5b5797deddbf24b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0f27aa770fdf0c7b3386ac37862226cb4b5215766d265e47c82323b2157966e6ce0d87b5e4081d8d9dcd549f45cd0f6527203b0025b0e6c62ce0780c81dae74
|
7
|
+
data.tar.gz: de86db0a2a0227e6bec231d11c378bffff42fa7911ccc0874bd3ed97fae7f73d0ac29ce55b31817f75bfa82c0b63daa79dabd28276a66e17e2748770450f6243
|
@@ -30,16 +30,19 @@ module StatelyDB
|
|
30
30
|
# @param [String] client_secret The StatelyDB client secret credential
|
31
31
|
# @param [String] client_id The StatelyDB client ID credential
|
32
32
|
# @param [String] access_key The StatelyDB access key credential
|
33
|
+
# @param [Float] base_retry_backoff_secs The base retry backoff in seconds
|
33
34
|
def initialize(
|
34
35
|
origin: "https://oauth.stately.cloud",
|
35
36
|
audience: "api.stately.cloud",
|
36
37
|
client_secret: ENV.fetch("STATELY_CLIENT_SECRET", nil),
|
37
38
|
client_id: ENV.fetch("STATELY_CLIENT_ID", nil),
|
38
|
-
access_key: ENV.fetch("STATELY_ACCESS_KEY", nil)
|
39
|
+
access_key: ENV.fetch("STATELY_ACCESS_KEY", nil),
|
40
|
+
base_retry_backoff_secs: 1
|
39
41
|
)
|
40
42
|
super()
|
41
43
|
@actor = Async::Actor.new(Actor.new(origin: origin, audience: audience,
|
42
|
-
client_secret: client_secret, client_id: client_id, access_key: access_key
|
44
|
+
client_secret: client_secret, client_id: client_id, access_key: access_key,
|
45
|
+
base_retry_backoff_secs: base_retry_backoff_secs))
|
43
46
|
# this initialization cannot happen in the constructor because it is async and must run on the event loop
|
44
47
|
# which is not available in the constructor
|
45
48
|
@actor.init
|
@@ -64,18 +67,23 @@ module StatelyDB
|
|
64
67
|
# @param [String] audience The OAuth Audience for the token
|
65
68
|
# @param [String] client_secret The StatelyDB client secret credential
|
66
69
|
# @param [String] client_id The StatelyDB client ID credential
|
70
|
+
# @param [String] access_key The StatelyDB access key credential
|
71
|
+
# @param [Float] base_retry_backoff_secs The base retry backoff in seconds
|
67
72
|
def initialize(
|
68
73
|
origin:,
|
69
74
|
audience:,
|
70
75
|
client_secret:,
|
71
76
|
client_id:,
|
72
|
-
access_key
|
77
|
+
access_key:,
|
78
|
+
base_retry_backoff_secs:
|
73
79
|
)
|
74
80
|
super()
|
75
81
|
|
76
82
|
@token_fetcher = nil
|
77
83
|
if !access_key.nil?
|
78
|
-
@token_fetcher = StatelyDB::Common::Auth::StatelyAccessTokenFetcher.new(
|
84
|
+
@token_fetcher = StatelyDB::Common::Auth::StatelyAccessTokenFetcher.new(
|
85
|
+
origin: origin, access_key: access_key, base_retry_backoff_secs: base_retry_backoff_secs
|
86
|
+
)
|
79
87
|
elsif !client_secret.nil? && !client_id.nil?
|
80
88
|
@token_fetcher = StatelyDB::Common::Auth::Auth0TokenFetcher.new(origin: origin, audience: audience,
|
81
89
|
client_secret: client_secret, client_id: client_id)
|
@@ -58,8 +58,6 @@ module StatelyDB
|
|
58
58
|
body = JSON.dump({ "client_id" => @client_id, client_secret: @client_secret, audience: @audience,
|
59
59
|
grant_type: DEFAULT_GRANT_TYPE })
|
60
60
|
Sync do
|
61
|
-
# TODO: Wrap this in a retry loop and parse errors like we
|
62
|
-
# do in the Go SDK.
|
63
61
|
response = @client.post("/oauth/token", headers, body)
|
64
62
|
raise "Auth request failed" if response.status != 200
|
65
63
|
|
@@ -77,11 +75,22 @@ module StatelyDB
|
|
77
75
|
|
78
76
|
# StatelyAccessTokenFetcher is a TokenFetcher that fetches tokens from the StatelyDB API
|
79
77
|
class StatelyAccessTokenFetcher < TokenFetcher
|
78
|
+
NON_RETRYABLE_ERRORS = [
|
79
|
+
GRPC::Core::StatusCodes::UNAUTHENTICATED,
|
80
|
+
GRPC::Core::StatusCodes::PERMISSION_DENIED,
|
81
|
+
GRPC::Core::StatusCodes::NOT_FOUND,
|
82
|
+
GRPC::Core::StatusCodes::UNIMPLEMENTED,
|
83
|
+
GRPC::Core::StatusCodes::INVALID_ARGUMENT
|
84
|
+
].freeze
|
85
|
+
RETRY_ATTEMPTS = 10
|
86
|
+
|
80
87
|
# @param [String] origin The origin of the OAuth server
|
81
88
|
# @param [String] access_key The StatelyDB access key credential
|
82
|
-
|
89
|
+
# @param [Float] base_retry_backoff_secs The base backoff time in seconds
|
90
|
+
def initialize(origin:, access_key:, base_retry_backoff_secs:)
|
83
91
|
super()
|
84
92
|
@access_key = access_key
|
93
|
+
@base_retry_backoff_secs = base_retry_backoff_secs
|
85
94
|
@channel = Common::Net.new_channel(endpoint: origin)
|
86
95
|
error_interceptor = Common::ErrorInterceptor.new
|
87
96
|
@stub = Stately::Auth::AuthService::Stub.new(nil, nil, channel_override: @channel,
|
@@ -91,14 +100,45 @@ module StatelyDB
|
|
91
100
|
# Fetch a new token from the StatelyDB API
|
92
101
|
# @return [TokenResult] The fetched TokenResult
|
93
102
|
def fetch
|
94
|
-
|
95
|
-
|
103
|
+
RETRY_ATTEMPTS.times do |i|
|
104
|
+
resp = @stub.get_auth_token(Stately::Auth::GetAuthTokenRequest.new(access_key: @access_key))
|
105
|
+
return TokenResult.new(token: resp.auth_token, expires_in_secs: resp.expires_in_s)
|
106
|
+
rescue StatelyDB::Error => e
|
107
|
+
# raise if it's the final attempt or if the error is not retryable
|
108
|
+
raise e unless self.class.retryable_error?(e) && i < RETRY_ATTEMPTS - 1
|
109
|
+
|
110
|
+
# exponential backoff
|
111
|
+
sleep(backoff(i, @base_retry_backoff_secs))
|
112
|
+
end
|
96
113
|
end
|
97
114
|
|
98
115
|
def close
|
99
116
|
@channel&.close
|
100
117
|
end
|
118
|
+
|
119
|
+
# Check if an error is retryable
|
120
|
+
# @param [StatelyDB::Error] err The error to check
|
121
|
+
# @return [Boolean] True if the error is retryable
|
122
|
+
def self.retryable_error?(err)
|
123
|
+
!NON_RETRYABLE_ERRORS.include?(err.code)
|
124
|
+
end
|
101
125
|
end
|
102
126
|
end
|
103
127
|
end
|
104
128
|
end
|
129
|
+
|
130
|
+
# backoff returns a duration to wait before retrying a request. `attempt` is
|
131
|
+
# the current attempt number, starting from 0 (e.g. the first attempt is 0,
|
132
|
+
# then 1, then 2...).
|
133
|
+
#
|
134
|
+
# @param [Integer] attempt The current attempt number
|
135
|
+
# @param [Float] base_backoff The base backoff time in seconds
|
136
|
+
# @return [Float] The duration in seconds to wait before retrying
|
137
|
+
def backoff(attempt, base_backoff)
|
138
|
+
# Double the base backoff time per attempt, starting with 1
|
139
|
+
exp = 2**attempt
|
140
|
+
# Add a full jitter to the backoff time, from no wait to 100% of the exponential backoff.
|
141
|
+
# See https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
|
142
|
+
jitter = rand
|
143
|
+
(exp * jitter * base_backoff)
|
144
|
+
end
|
data/sig/statelydb.rbi
CHANGED
@@ -636,11 +636,22 @@ module StatelyDB
|
|
636
636
|
|
637
637
|
# StatelyAccessTokenFetcher is a TokenFetcher that fetches tokens from the StatelyDB API
|
638
638
|
class StatelyAccessTokenFetcher < StatelyDB::Common::Auth::TokenFetcher
|
639
|
+
NON_RETRYABLE_ERRORS = T.let([
|
640
|
+
GRPC::Core::StatusCodes::UNAUTHENTICATED,
|
641
|
+
GRPC::Core::StatusCodes::PERMISSION_DENIED,
|
642
|
+
GRPC::Core::StatusCodes::NOT_FOUND,
|
643
|
+
GRPC::Core::StatusCodes::UNIMPLEMENTED,
|
644
|
+
GRPC::Core::StatusCodes::INVALID_ARGUMENT
|
645
|
+
].freeze, T.untyped)
|
646
|
+
RETRY_ATTEMPTS = T.let(10, T.untyped)
|
647
|
+
|
639
648
|
# _@param_ `origin` — The origin of the OAuth server
|
640
649
|
#
|
641
650
|
# _@param_ `access_key` — The StatelyDB access key credential
|
642
|
-
|
643
|
-
|
651
|
+
#
|
652
|
+
# _@param_ `base_retry_backoff_secs` — The base backoff time in seconds
|
653
|
+
sig { params(origin: String, access_key: String, base_retry_backoff_secs: Float).void }
|
654
|
+
def initialize(origin:, access_key:, base_retry_backoff_secs:); end
|
644
655
|
|
645
656
|
# Fetch a new token from the StatelyDB API
|
646
657
|
#
|
@@ -650,6 +661,14 @@ module StatelyDB
|
|
650
661
|
|
651
662
|
sig { returns(T.untyped) }
|
652
663
|
def close; end
|
664
|
+
|
665
|
+
# Check if an error is retryable
|
666
|
+
#
|
667
|
+
# _@param_ `err` — The error to check
|
668
|
+
#
|
669
|
+
# _@return_ — True if the error is retryable
|
670
|
+
sig { params(err: StatelyDB::Error).returns(T::Boolean) }
|
671
|
+
def self.retryable_error?(err); end
|
653
672
|
end
|
654
673
|
|
655
674
|
# TokenProvider is an abstract base class that should be extended
|
@@ -682,16 +701,19 @@ module StatelyDB
|
|
682
701
|
# _@param_ `client_id` — The StatelyDB client ID credential
|
683
702
|
#
|
684
703
|
# _@param_ `access_key` — The StatelyDB access key credential
|
704
|
+
#
|
705
|
+
# _@param_ `base_retry_backoff_secs` — The base retry backoff in seconds
|
685
706
|
sig do
|
686
707
|
params(
|
687
708
|
origin: String,
|
688
709
|
audience: String,
|
689
710
|
client_secret: String,
|
690
711
|
client_id: String,
|
691
|
-
access_key: String
|
712
|
+
access_key: String,
|
713
|
+
base_retry_backoff_secs: Float
|
692
714
|
).void
|
693
715
|
end
|
694
|
-
def initialize(origin: "https://oauth.stately.cloud", audience: "api.stately.cloud", client_secret: ENV.fetch("STATELY_CLIENT_SECRET", nil), client_id: ENV.fetch("STATELY_CLIENT_ID", nil), access_key: ENV.fetch("STATELY_ACCESS_KEY", nil)); end
|
716
|
+
def initialize(origin: "https://oauth.stately.cloud", audience: "api.stately.cloud", client_secret: ENV.fetch("STATELY_CLIENT_SECRET", nil), client_id: ENV.fetch("STATELY_CLIENT_ID", nil), access_key: ENV.fetch("STATELY_ACCESS_KEY", nil), base_retry_backoff_secs: 1); end
|
695
717
|
|
696
718
|
# Close the token provider and kill any background operations
|
697
719
|
# This just invokes the close method on the actor which should do the cleanup
|
@@ -714,16 +736,21 @@ module StatelyDB
|
|
714
736
|
# _@param_ `client_secret` — The StatelyDB client secret credential
|
715
737
|
#
|
716
738
|
# _@param_ `client_id` — The StatelyDB client ID credential
|
739
|
+
#
|
740
|
+
# _@param_ `access_key` — The StatelyDB access key credential
|
741
|
+
#
|
742
|
+
# _@param_ `base_retry_backoff_secs` — The base retry backoff in seconds
|
717
743
|
sig do
|
718
744
|
params(
|
719
745
|
origin: String,
|
720
746
|
audience: String,
|
721
747
|
client_secret: String,
|
722
748
|
client_id: String,
|
723
|
-
access_key:
|
749
|
+
access_key: String,
|
750
|
+
base_retry_backoff_secs: Float
|
724
751
|
).void
|
725
752
|
end
|
726
|
-
def initialize(origin:, audience:, client_secret:, client_id:, access_key:); end
|
753
|
+
def initialize(origin:, audience:, client_secret:, client_id:, access_key:, base_retry_backoff_secs:); end
|
727
754
|
|
728
755
|
# Initialize the actor. This runs on the actor thread which means
|
729
756
|
# we can dispatch async operations here.
|
data/sig/statelydb.rbs
CHANGED
@@ -550,10 +550,15 @@ module StatelyDB
|
|
550
550
|
|
551
551
|
# StatelyAccessTokenFetcher is a TokenFetcher that fetches tokens from the StatelyDB API
|
552
552
|
class StatelyAccessTokenFetcher < StatelyDB::Common::Auth::TokenFetcher
|
553
|
+
NON_RETRYABLE_ERRORS: untyped
|
554
|
+
RETRY_ATTEMPTS: untyped
|
555
|
+
|
553
556
|
# _@param_ `origin` — The origin of the OAuth server
|
554
557
|
#
|
555
558
|
# _@param_ `access_key` — The StatelyDB access key credential
|
556
|
-
|
559
|
+
#
|
560
|
+
# _@param_ `base_retry_backoff_secs` — The base backoff time in seconds
|
561
|
+
def initialize: (origin: String, access_key: String, base_retry_backoff_secs: Float) -> void
|
557
562
|
|
558
563
|
# Fetch a new token from the StatelyDB API
|
559
564
|
#
|
@@ -561,6 +566,13 @@ module StatelyDB
|
|
561
566
|
def fetch: () -> TokenResult
|
562
567
|
|
563
568
|
def close: () -> untyped
|
569
|
+
|
570
|
+
# Check if an error is retryable
|
571
|
+
#
|
572
|
+
# _@param_ `err` — The error to check
|
573
|
+
#
|
574
|
+
# _@return_ — True if the error is retryable
|
575
|
+
def self.retryable_error?: (StatelyDB::Error err) -> bool
|
564
576
|
end
|
565
577
|
|
566
578
|
# TokenProvider is an abstract base class that should be extended
|
@@ -591,12 +603,15 @@ module StatelyDB
|
|
591
603
|
# _@param_ `client_id` — The StatelyDB client ID credential
|
592
604
|
#
|
593
605
|
# _@param_ `access_key` — The StatelyDB access key credential
|
606
|
+
#
|
607
|
+
# _@param_ `base_retry_backoff_secs` — The base retry backoff in seconds
|
594
608
|
def initialize: (
|
595
609
|
?origin: String,
|
596
610
|
?audience: String,
|
597
611
|
?client_secret: String,
|
598
612
|
?client_id: String,
|
599
|
-
?access_key: String
|
613
|
+
?access_key: String,
|
614
|
+
?base_retry_backoff_secs: Float
|
600
615
|
) -> void
|
601
616
|
|
602
617
|
# Close the token provider and kill any background operations
|
@@ -618,12 +633,17 @@ module StatelyDB
|
|
618
633
|
# _@param_ `client_secret` — The StatelyDB client secret credential
|
619
634
|
#
|
620
635
|
# _@param_ `client_id` — The StatelyDB client ID credential
|
636
|
+
#
|
637
|
+
# _@param_ `access_key` — The StatelyDB access key credential
|
638
|
+
#
|
639
|
+
# _@param_ `base_retry_backoff_secs` — The base retry backoff in seconds
|
621
640
|
def initialize: (
|
622
641
|
origin: String,
|
623
642
|
audience: String,
|
624
643
|
client_secret: String,
|
625
644
|
client_id: String,
|
626
|
-
access_key:
|
645
|
+
access_key: String,
|
646
|
+
base_retry_backoff_secs: Float
|
627
647
|
) -> void
|
628
648
|
|
629
649
|
# Initialize the actor. This runs on the actor thread which means
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statelydb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.15.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stately Cloud, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async
|