cyclone_lariat 0.2.1
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 +7 -0
- data/.gitignore +18 -0
- data/.rspec +3 -0
- data/.rubocop.yml +48 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +151 -0
- data/README.md +157 -0
- data/Rakefile +11 -0
- data/config/db.example.rb +9 -0
- data/config/db.rb +9 -0
- data/cyclone_lariat.gemspec +52 -0
- data/db/migrate/01_add_uuid_extensions.rb +15 -0
- data/db/migrate/02_add_events.rb +18 -0
- data/docs/_imgs/lariat.jpg +0 -0
- data/lib/cyclone_lariat.rb +10 -0
- data/lib/cyclone_lariat/client.rb +98 -0
- data/lib/cyclone_lariat/errors.rb +22 -0
- data/lib/cyclone_lariat/event.rb +81 -0
- data/lib/cyclone_lariat/events_repo.rb +50 -0
- data/lib/cyclone_lariat/middleware.rb +57 -0
- data/lib/cyclone_lariat/version.rb +5 -0
- data/lib/tasks/db.rake +55 -0
- metadata +294 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b29f194e1ee444b5621fee3ad9be7547ad612c34acf8cf451d5be0f20976cc4e
|
4
|
+
data.tar.gz: efdedb4530a004672b9c671c02b899fddedaa1d45b9876d28bce672f86f88812
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4c784a8c6ec54fef60a529a09d6a45f9dd32bab493e2acabdabed7e2039e743cb547e132a38522ee1b8473a1e2f21644b8d7a25d8bd1daca498e2bef5cd390ee
|
7
|
+
data.tar.gz: 85628b6886b4a82b639aa0f271b199e9cd85db4cbb316d4621637ca062ad996892f8c171ad32367a64f213b1ebcdd5e495e6f7cdb00f518923e87ecfe41a2610
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
##
|
2
|
+
# Bug with Travis rubocop and rainbow gem
|
3
|
+
# resolve:
|
4
|
+
# https://github.com/rubocop-hq/rubocop/issues/6398#issuecomment-431898694
|
5
|
+
inherit_mode:
|
6
|
+
merge:
|
7
|
+
- Exclude
|
8
|
+
|
9
|
+
AllCops:
|
10
|
+
TargetRubyVersion: 2.6
|
11
|
+
Exclude:
|
12
|
+
- Rakefile
|
13
|
+
UseCache: true
|
14
|
+
NewCops: enable
|
15
|
+
|
16
|
+
Metrics/LineLength:
|
17
|
+
Max: 120
|
18
|
+
IgnoredPatterns: ['\s*\#\s.*$']
|
19
|
+
Exclude:
|
20
|
+
- 'spec/**/*'
|
21
|
+
|
22
|
+
Style/Documentation:
|
23
|
+
Exclude:
|
24
|
+
- '**/*'
|
25
|
+
|
26
|
+
Metrics/ParameterLists:
|
27
|
+
Exclude:
|
28
|
+
- '**/*'
|
29
|
+
|
30
|
+
Style/AccessorGrouping:
|
31
|
+
Exclude:
|
32
|
+
- 'lib/cyclone_lariat/event.rb'
|
33
|
+
|
34
|
+
Metrics/CyclomaticComplexity:
|
35
|
+
Exclude:
|
36
|
+
- 'lib/cyclone_lariat/event.rb'
|
37
|
+
-
|
38
|
+
Metrics/PerceivedComplexity:
|
39
|
+
Exclude:
|
40
|
+
- 'lib/cyclone_lariat/event.rb'
|
41
|
+
|
42
|
+
Metrics/AbcSize:
|
43
|
+
Exclude:
|
44
|
+
- '**/*'
|
45
|
+
|
46
|
+
Metrics/BlockLength:
|
47
|
+
Exclude:
|
48
|
+
- '**/*'
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
cyclone-lariat
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.6.0
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## [0.2.0] - 2021-06-2
|
8
|
+
Changed
|
9
|
+
- Fix can load from database if error_details is nil
|
10
|
+
|
11
|
+
## [0.2.0] - 2021-06-2
|
12
|
+
Added
|
13
|
+
- Complete tests
|
14
|
+
- Production ready
|
15
|
+
|
16
|
+
## [0.1.0] - 2021-05-24
|
17
|
+
- Init project
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
cyclone_lariat (0.2.1)
|
5
|
+
aws-sdk-sns
|
6
|
+
luna_park (~> 0.11)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
addressable (2.7.0)
|
12
|
+
public_suffix (>= 2.0.2, < 5.0)
|
13
|
+
ast (2.4.2)
|
14
|
+
aws-eventstream (1.1.1)
|
15
|
+
aws-partitions (1.462.0)
|
16
|
+
aws-sdk-core (3.114.0)
|
17
|
+
aws-eventstream (~> 1, >= 1.0.2)
|
18
|
+
aws-partitions (~> 1, >= 1.239.0)
|
19
|
+
aws-sigv4 (~> 1.1)
|
20
|
+
jmespath (~> 1.0)
|
21
|
+
aws-sdk-sns (1.40.0)
|
22
|
+
aws-sdk-core (~> 3, >= 3.112.0)
|
23
|
+
aws-sigv4 (~> 1.1)
|
24
|
+
aws-sigv4 (1.2.3)
|
25
|
+
aws-eventstream (~> 1, >= 1.0.2)
|
26
|
+
byebug (11.1.3)
|
27
|
+
coderay (1.1.3)
|
28
|
+
concurrent-ruby (1.1.8)
|
29
|
+
crack (0.4.5)
|
30
|
+
rexml
|
31
|
+
database_cleaner-core (2.0.1)
|
32
|
+
database_cleaner-sequel (2.0.0)
|
33
|
+
database_cleaner-core (~> 2.0.0)
|
34
|
+
sequel
|
35
|
+
diff-lcs (1.4.4)
|
36
|
+
docile (1.4.0)
|
37
|
+
dry-configurable (0.12.1)
|
38
|
+
concurrent-ruby (~> 1.0)
|
39
|
+
dry-core (~> 0.5, >= 0.5.0)
|
40
|
+
dry-container (0.7.2)
|
41
|
+
concurrent-ruby (~> 1.0)
|
42
|
+
dry-configurable (~> 0.1, >= 0.1.3)
|
43
|
+
dry-core (0.5.0)
|
44
|
+
concurrent-ruby (~> 1.0)
|
45
|
+
dry-equalizer (0.3.0)
|
46
|
+
dry-inflector (0.2.0)
|
47
|
+
dry-initializer (3.0.4)
|
48
|
+
dry-logic (1.2.0)
|
49
|
+
concurrent-ruby (~> 1.0)
|
50
|
+
dry-core (~> 0.5, >= 0.5)
|
51
|
+
dry-schema (1.6.2)
|
52
|
+
concurrent-ruby (~> 1.0)
|
53
|
+
dry-configurable (~> 0.8, >= 0.8.3)
|
54
|
+
dry-core (~> 0.5, >= 0.5)
|
55
|
+
dry-initializer (~> 3.0)
|
56
|
+
dry-logic (~> 1.0)
|
57
|
+
dry-types (~> 1.5)
|
58
|
+
dry-types (1.5.1)
|
59
|
+
concurrent-ruby (~> 1.0)
|
60
|
+
dry-container (~> 0.3)
|
61
|
+
dry-core (~> 0.5, >= 0.5)
|
62
|
+
dry-inflector (~> 0.1, >= 0.1.2)
|
63
|
+
dry-logic (~> 1.0, >= 1.0.2)
|
64
|
+
dry-validation (1.6.0)
|
65
|
+
concurrent-ruby (~> 1.0)
|
66
|
+
dry-container (~> 0.7, >= 0.7.1)
|
67
|
+
dry-core (~> 0.4)
|
68
|
+
dry-equalizer (~> 0.2)
|
69
|
+
dry-initializer (~> 3.0)
|
70
|
+
dry-schema (~> 1.5, >= 1.5.2)
|
71
|
+
hashdiff (1.0.1)
|
72
|
+
jmespath (1.4.0)
|
73
|
+
luna_park (0.11.1)
|
74
|
+
method_source (1.0.0)
|
75
|
+
parallel (1.20.1)
|
76
|
+
parser (3.0.1.1)
|
77
|
+
ast (~> 2.4.1)
|
78
|
+
pg (1.2.3)
|
79
|
+
pry (0.13.1)
|
80
|
+
coderay (~> 1.1)
|
81
|
+
method_source (~> 1.0)
|
82
|
+
pry-byebug (3.9.0)
|
83
|
+
byebug (~> 11.0)
|
84
|
+
pry (~> 0.13.0)
|
85
|
+
public_suffix (4.0.6)
|
86
|
+
rainbow (3.0.0)
|
87
|
+
rake (13.0.3)
|
88
|
+
regexp_parser (2.1.1)
|
89
|
+
rexml (3.2.5)
|
90
|
+
rspec (3.10.0)
|
91
|
+
rspec-core (~> 3.10.0)
|
92
|
+
rspec-expectations (~> 3.10.0)
|
93
|
+
rspec-mocks (~> 3.10.0)
|
94
|
+
rspec-core (3.10.1)
|
95
|
+
rspec-support (~> 3.10.0)
|
96
|
+
rspec-expectations (3.10.1)
|
97
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
98
|
+
rspec-support (~> 3.10.0)
|
99
|
+
rspec-mocks (3.10.2)
|
100
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
101
|
+
rspec-support (~> 3.10.0)
|
102
|
+
rspec-support (3.10.2)
|
103
|
+
rubocop (0.93.1)
|
104
|
+
parallel (~> 1.10)
|
105
|
+
parser (>= 2.7.1.5)
|
106
|
+
rainbow (>= 2.2.2, < 4.0)
|
107
|
+
regexp_parser (>= 1.8)
|
108
|
+
rexml
|
109
|
+
rubocop-ast (>= 0.6.0)
|
110
|
+
ruby-progressbar (~> 1.7)
|
111
|
+
unicode-display_width (>= 1.4.0, < 2.0)
|
112
|
+
rubocop-ast (1.5.0)
|
113
|
+
parser (>= 3.0.1.1)
|
114
|
+
ruby-progressbar (1.11.0)
|
115
|
+
sequel (5.44.0)
|
116
|
+
simplecov (0.21.2)
|
117
|
+
docile (~> 1.1)
|
118
|
+
simplecov-html (~> 0.11)
|
119
|
+
simplecov_json_formatter (~> 0.1)
|
120
|
+
simplecov-html (0.12.3)
|
121
|
+
simplecov_json_formatter (0.1.3)
|
122
|
+
timecop (0.9.4)
|
123
|
+
unicode-display_width (1.7.0)
|
124
|
+
webmock (3.7.6)
|
125
|
+
addressable (>= 2.3.6)
|
126
|
+
crack (>= 0.3.2)
|
127
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
128
|
+
yard (0.9.26)
|
129
|
+
|
130
|
+
PLATFORMS
|
131
|
+
x86_64-linux
|
132
|
+
|
133
|
+
DEPENDENCIES
|
134
|
+
bundler (~> 2.1)
|
135
|
+
byebug (~> 11.1)
|
136
|
+
cyclone_lariat!
|
137
|
+
database_cleaner-sequel (~> 2.0)
|
138
|
+
dry-validation (~> 1.1)
|
139
|
+
pg (~> 1.2)
|
140
|
+
pry (~> 0.13)
|
141
|
+
pry-byebug (~> 3.9)
|
142
|
+
rake (~> 13.0)
|
143
|
+
rspec (~> 3.0)
|
144
|
+
rubocop (~> 0.87)
|
145
|
+
simplecov (~> 0.18)
|
146
|
+
timecop (~> 0.9)
|
147
|
+
webmock (~> 3.7.0)
|
148
|
+
yard (~> 0.9)
|
149
|
+
|
150
|
+
BUNDLED WITH
|
151
|
+
2.2.19
|
data/README.md
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
# Cyclone lariat
|
2
|
+
|
3
|
+
This is gem work like middleware for [shoryuken](https://github.com/ruby-shoryuken/shoryuken). It save all events to database. And catch and produce all exceptions.
|
4
|
+
|
5
|
+

|
6
|
+
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
# Gemfile
|
10
|
+
|
11
|
+
# If use client or middleware
|
12
|
+
gem 'cyclone_lariat', require: false
|
13
|
+
|
14
|
+
# If use client
|
15
|
+
gem 'cyclone_lariat'
|
16
|
+
```
|
17
|
+
|
18
|
+
|
19
|
+
## Client
|
20
|
+
|
21
|
+
You can use client directly
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'cyclone_lariat/client' # If require: false in Gemfile
|
25
|
+
|
26
|
+
client = CycloneLariat::Client.new(
|
27
|
+
key: APP_CONF.aws.key,
|
28
|
+
secret_key: APP_CONF.aws.secret_key,
|
29
|
+
region: APP_CONF.aws.region,
|
30
|
+
version: 1, # at default 1
|
31
|
+
publisher: 'pilot',
|
32
|
+
instance: INSTANCE # at default :prod
|
33
|
+
)
|
34
|
+
```
|
35
|
+
|
36
|
+
You can don't define topic, and it's name will be defined automatically
|
37
|
+
```ruby
|
38
|
+
# event_type data topic
|
39
|
+
client.publish_event 'email_is_created', data: { mail: 'john.doe@example.com' } # prod-event-fanout-pilot-email_is_created
|
40
|
+
client.publish_event 'email_is_removed', data: { mail: 'john.doe@example.com' } # prod-event-fanout-pilot-email_is_removed
|
41
|
+
```
|
42
|
+
Or you can define it by handle. For example, if you want to send different events to same channel.
|
43
|
+
```ruby
|
44
|
+
# event_type data topic
|
45
|
+
client.publish_event 'email_is_created', data: { mail: 'john.doe@example.com' }, to: 'prod-event-fanout-pilot-emails'
|
46
|
+
client.publish_event 'email_is_removed', data: { mail: 'john.doe@example.com' }, to: 'prod-event-fanout-pilot-emails'
|
47
|
+
```
|
48
|
+
|
49
|
+
Or you can use client as Repo.
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
require 'cyclone_lariat/client' # If require: false in Gemfile
|
53
|
+
|
54
|
+
class YourClient < CycloneLariat::Client
|
55
|
+
version 1
|
56
|
+
publisher 'pilot'
|
57
|
+
instance 'stage'
|
58
|
+
|
59
|
+
def email_is_created(mail)
|
60
|
+
publish event( 'email_is_created',
|
61
|
+
data: { mail: mail }
|
62
|
+
),
|
63
|
+
to: APP_CONF.aws.fanout.emails
|
64
|
+
end
|
65
|
+
|
66
|
+
def email_is_removed(mail)
|
67
|
+
publish event( 'email_is_removed',
|
68
|
+
data: { mail: mail }
|
69
|
+
),
|
70
|
+
to: APP_CONF.aws.fanout.email
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Init repo
|
75
|
+
client = YourClient.new(key: APP_CONF.aws.key, secret_key: APP_CONF.aws.secret_key, region: APP_CONF.aws.region)
|
76
|
+
|
77
|
+
# And send topics
|
78
|
+
client.email_is_created 'john.doe@example.com'
|
79
|
+
client.email_is_removed 'john.doe@example.com'
|
80
|
+
```
|
81
|
+
|
82
|
+
# Middleware
|
83
|
+
If you use middleware:
|
84
|
+
- Store all events to dataset
|
85
|
+
- Notify every input sqs message
|
86
|
+
- Notify every error
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
require 'cyclone_lariat/middleware' # If require: false in Gemfile
|
90
|
+
|
91
|
+
class Receiver
|
92
|
+
include Shoryuken::Worker
|
93
|
+
|
94
|
+
DB = Sequel.connect(host: 'localhost', user: 'ruby')
|
95
|
+
|
96
|
+
shoryuken_options auto_delete: true,
|
97
|
+
body_parser: ->(sqs_msg) {
|
98
|
+
JSON.parse(sqs_msg.body, symbolize_names: true)
|
99
|
+
},
|
100
|
+
queue: 'your_sqs_queue_name'
|
101
|
+
|
102
|
+
server_middleware do |chain|
|
103
|
+
|
104
|
+
# Options dataset, errors_notifier and message_notifier is optionals.
|
105
|
+
# If you dont define notifiers - middleware does not notify
|
106
|
+
# If you dont define dataset - middleware does store events in db
|
107
|
+
chain.add CycloneLariat::Middleware,
|
108
|
+
dataset: DB[:events],
|
109
|
+
errors_notifier: LunaPark::Notifiers::Sentry.new,
|
110
|
+
message_notifier: LunaPark::Notifiers::Log.new(min_lvl: :debug, format: :pretty_json)
|
111
|
+
end
|
112
|
+
|
113
|
+
def perform(sqs_message, sqs_message_body)
|
114
|
+
# Your logic here
|
115
|
+
end
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
## Migrations
|
120
|
+
Before use events storage add and apply this two migrations
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
|
124
|
+
# First one
|
125
|
+
|
126
|
+
Sequel.migration do
|
127
|
+
up do
|
128
|
+
run <<-SQL
|
129
|
+
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
130
|
+
SQL
|
131
|
+
end
|
132
|
+
|
133
|
+
down do
|
134
|
+
run <<-SQL
|
135
|
+
DROP EXTENSION IF EXISTS "uuid-ossp";
|
136
|
+
SQL
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# The second one:
|
141
|
+
Sequel.migration do
|
142
|
+
change do
|
143
|
+
create_table :events do
|
144
|
+
column :uuid, :uuid, primary_key: true
|
145
|
+
String :type, null: false
|
146
|
+
Integer :version, null: false
|
147
|
+
String :publisher, null: false
|
148
|
+
column :data, :json, null: false
|
149
|
+
String :error_message, null: true, default: nil
|
150
|
+
column :error_details, :json, null: true, default: nil
|
151
|
+
DateTime :sent_at, null: true, default: nil
|
152
|
+
DateTime :received_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
153
|
+
DateTime :processed_at, null: true, default: nil
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
```
|
data/Rakefile
ADDED
data/config/db.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'cyclone_lariat/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'cyclone_lariat'
|
9
|
+
spec.version = CycloneLariat::VERSION
|
10
|
+
spec.authors = ['Alexander Kudrin', 'Philip Sorokin']
|
11
|
+
spec.email = ['kudrin.alexander@gmail.com']
|
12
|
+
|
13
|
+
spec.summary = 'Shoryuken middleware for LunaPark based application.'
|
14
|
+
spec.homepage = 'https://am-team.github.io/cyclone_lariat/#/'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
spec.required_ruby_version = '>= 2.6.0'
|
17
|
+
|
18
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
19
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
20
|
+
if spec.respond_to?(:metadata)
|
21
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
22
|
+
else
|
23
|
+
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
24
|
+
'public gem pushes.'
|
25
|
+
end
|
26
|
+
spec.metadata['yard.run'] = 'yri'
|
27
|
+
|
28
|
+
# Specify which files should be added to the gem when it is released.
|
29
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
30
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
31
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
32
|
+
end
|
33
|
+
spec.require_paths = ['lib']
|
34
|
+
|
35
|
+
spec.add_dependency 'aws-sdk-sns'
|
36
|
+
spec.add_dependency 'luna_park', '~> 0.11'
|
37
|
+
|
38
|
+
spec.add_development_dependency 'bundler', '~> 2.1'
|
39
|
+
spec.add_development_dependency 'byebug', '~> 11.1'
|
40
|
+
spec.add_development_dependency 'database_cleaner-sequel', '~> 2.0'
|
41
|
+
spec.add_development_dependency 'dry-validation', '~> 1.1'
|
42
|
+
spec.add_development_dependency 'pg', '~> 1.2'
|
43
|
+
spec.add_development_dependency 'pry', '~> 0.13'
|
44
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.9'
|
45
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
46
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
47
|
+
spec.add_development_dependency 'rubocop', '~> 0.87'
|
48
|
+
spec.add_development_dependency 'simplecov', '~> 0.18'
|
49
|
+
spec.add_development_dependency 'timecop', '~> 0.9'
|
50
|
+
spec.add_development_dependency 'webmock', '~> 3.7.0'
|
51
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
52
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Sequel.migration do
|
4
|
+
change do
|
5
|
+
create_table :events do
|
6
|
+
column :uuid, :uuid, primary_key: true
|
7
|
+
String :type, null: false
|
8
|
+
Integer :version, null: false
|
9
|
+
String :publisher, null: false
|
10
|
+
column :data, :json, null: false
|
11
|
+
String :error_message, null: true, default: nil
|
12
|
+
column :error_details, :json, null: true, default: nil
|
13
|
+
DateTime :sent_at, null: true, default: nil
|
14
|
+
DateTime :received_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
15
|
+
DateTime :processed_at, null: true, default: nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
Binary file
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'cyclone_lariat/client'
|
4
|
+
require_relative 'cyclone_lariat/errors'
|
5
|
+
require_relative 'cyclone_lariat/event'
|
6
|
+
require_relative 'cyclone_lariat/events_repo'
|
7
|
+
require_relative 'cyclone_lariat/middleware'
|
8
|
+
require_relative 'cyclone_lariat/version'
|
9
|
+
|
10
|
+
module CycloneLariat; end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'aws-sdk-sns'
|
4
|
+
require 'luna_park/extensions/injector'
|
5
|
+
require_relative 'event'
|
6
|
+
require_relative 'errors'
|
7
|
+
|
8
|
+
module CycloneLariat
|
9
|
+
class Client
|
10
|
+
include LunaPark::Extensions::Injector
|
11
|
+
|
12
|
+
dependency(:aws_sns_client_class) { Aws::SNS::Client }
|
13
|
+
dependency(:aws_credentials_class) { Aws::Credentials }
|
14
|
+
|
15
|
+
DEFAULT_VERSION = 1
|
16
|
+
DEFAULT_INSTANCE = :prod
|
17
|
+
SNS_SUFFIX = :fanout
|
18
|
+
|
19
|
+
def initialize(key:, secret_key:, region:, version: nil, publisher: nil, instance: nil)
|
20
|
+
@key = key
|
21
|
+
@secret_key = secret_key
|
22
|
+
@region = region
|
23
|
+
@version = version
|
24
|
+
@publisher = publisher
|
25
|
+
@instance = instance
|
26
|
+
end
|
27
|
+
|
28
|
+
def event(type, data: {}, version: self.version, uuid: SecureRandom.uuid)
|
29
|
+
Event.wrap(
|
30
|
+
uuid: uuid,
|
31
|
+
type: type,
|
32
|
+
sent_at: Time.now.iso8601,
|
33
|
+
version: version,
|
34
|
+
publisher: publisher,
|
35
|
+
data: data
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def publish(msg, to: nil)
|
40
|
+
topic = to || [instance, msg.kind, SNS_SUFFIX, publisher, msg.type].join('-')
|
41
|
+
|
42
|
+
aws_client.publish(
|
43
|
+
topic_arn: topic_arn(topic),
|
44
|
+
message: msg.to_json
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
def publish_event(type, data: {}, version: self.version, uuid: SecureRandom.uuid, to: nil)
|
49
|
+
publish event(type, data: data, version: version, uuid: uuid), to: to
|
50
|
+
end
|
51
|
+
|
52
|
+
class << self
|
53
|
+
def version(version = nil)
|
54
|
+
version.nil? ? @version || DEFAULT_VERSION : @version = version
|
55
|
+
end
|
56
|
+
|
57
|
+
def instance(instance = nil)
|
58
|
+
instance.nil? ? @instance || DEFAULT_INSTANCE : @instance = instance
|
59
|
+
end
|
60
|
+
|
61
|
+
def publisher(publisher = nil)
|
62
|
+
publisher.nil? ? @publisher || (raise 'You should define publisher') : @publisher = publisher
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def version
|
67
|
+
@version ||= self.class.version
|
68
|
+
end
|
69
|
+
|
70
|
+
def publisher
|
71
|
+
@publisher ||= self.class.publisher
|
72
|
+
end
|
73
|
+
|
74
|
+
def instance
|
75
|
+
@instance ||= self.class.instance
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
attr_reader :key, :secret_key, :region
|
81
|
+
|
82
|
+
def topic_arn(topic_name)
|
83
|
+
list = aws_client.list_topics.topics
|
84
|
+
topic = list.find { |t| t.topic_arn.match?(topic_name) }
|
85
|
+
raise Errors::TopicNotFound.new(expected_topic: topic_name, existed_topics: list.map(&:topic_arn)) if topic.nil?
|
86
|
+
|
87
|
+
topic.topic_arn
|
88
|
+
end
|
89
|
+
|
90
|
+
def aws_client
|
91
|
+
@aws_client ||= aws_sns_client_class.new(credentials: aws_credentials, region: region)
|
92
|
+
end
|
93
|
+
|
94
|
+
def aws_credentials
|
95
|
+
@aws_credentials ||= aws_credentials_class.new(key, secret_key)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'luna_park/errors/system'
|
4
|
+
require 'luna_park/errors/business'
|
5
|
+
|
6
|
+
module CycloneLariat
|
7
|
+
module Errors
|
8
|
+
class TopicNotFound < LunaPark::Errors::System
|
9
|
+
message { |d| "Could not found topic: `#{d[:expected_topic]}`" }
|
10
|
+
end
|
11
|
+
|
12
|
+
class ProcessingEventLogic < LunaPark::Errors::Business
|
13
|
+
attr_writer :message, :details
|
14
|
+
|
15
|
+
def ==(other)
|
16
|
+
other.is_a?(LunaPark::Errors::Business) &&
|
17
|
+
other.message == message &&
|
18
|
+
other.details == details
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'luna_park/entities/attributable'
|
4
|
+
require_relative 'errors'
|
5
|
+
|
6
|
+
module CycloneLariat
|
7
|
+
class Event < LunaPark::Entities::Attributable
|
8
|
+
KIND = 'event'
|
9
|
+
|
10
|
+
attr :uuid, String, :new
|
11
|
+
attr :publisher, String, :new
|
12
|
+
attr :type, String, :new
|
13
|
+
attr :error
|
14
|
+
attr :version
|
15
|
+
attr :data
|
16
|
+
|
17
|
+
attr_reader :sent_at,
|
18
|
+
:processed_at,
|
19
|
+
:received_at
|
20
|
+
|
21
|
+
def kind
|
22
|
+
KIND
|
23
|
+
end
|
24
|
+
|
25
|
+
def version=(value)
|
26
|
+
@version = Integer(value)
|
27
|
+
end
|
28
|
+
|
29
|
+
def sent_at=(value)
|
30
|
+
@sent_at = wrap_time(value)
|
31
|
+
end
|
32
|
+
|
33
|
+
def received_at=(value)
|
34
|
+
@received_at = wrap_time(value)
|
35
|
+
end
|
36
|
+
|
37
|
+
def processed_at=(value)
|
38
|
+
@processed_at = wrap_time(value)
|
39
|
+
end
|
40
|
+
|
41
|
+
def error_message=(txt)
|
42
|
+
@error ||= Errors::ProcessingEventLogic.new
|
43
|
+
@error.message = txt
|
44
|
+
end
|
45
|
+
|
46
|
+
def error_details=(details)
|
47
|
+
@error ||= Errors::ProcessingEventLogic.new
|
48
|
+
@error.details = details
|
49
|
+
end
|
50
|
+
|
51
|
+
def ==(other)
|
52
|
+
kind == other.kind &&
|
53
|
+
uuid == other.uuid &&
|
54
|
+
publisher == other.publisher &&
|
55
|
+
type == other.type &&
|
56
|
+
error&.message == other.error&.message &&
|
57
|
+
error&.details == other.error&.details &&
|
58
|
+
version == other.version &&
|
59
|
+
sent_at.to_i == other.sent_at.to_i &&
|
60
|
+
received_at.to_i == other.received_at.to_i
|
61
|
+
processed_at.to_i == other.processed_at.to_i
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_json(*args)
|
65
|
+
hash = serialize
|
66
|
+
hash[:type] = [kind, hash[:type]].join '_'
|
67
|
+
hash.to_json(*args)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def wrap_time(value)
|
73
|
+
case value
|
74
|
+
when String then Time.parse(value)
|
75
|
+
when Time then value
|
76
|
+
when NilClass then nil
|
77
|
+
else raise ArgumentError, "Unknown type `#{value.class}`"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'event'
|
4
|
+
|
5
|
+
module CycloneLariat
|
6
|
+
class EventsRepo
|
7
|
+
attr_reader :dataset
|
8
|
+
|
9
|
+
def initialize(dataset)
|
10
|
+
@dataset = dataset
|
11
|
+
end
|
12
|
+
|
13
|
+
def create(event)
|
14
|
+
dataset.insert(
|
15
|
+
uuid: event.uuid,
|
16
|
+
type: event.type,
|
17
|
+
publisher: event.publisher,
|
18
|
+
data: JSON.generate(event.data),
|
19
|
+
error_message: event.error&.message,
|
20
|
+
error_details: JSON.generate(event.error&.details),
|
21
|
+
version: event.version,
|
22
|
+
sent_at: event.sent_at
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def exists?(uuid:)
|
27
|
+
dataset.where(uuid: uuid).limit(1).any?
|
28
|
+
end
|
29
|
+
|
30
|
+
def processed!(uuid:)
|
31
|
+
!dataset.where(uuid: uuid).update(processed_at: Sequel.function(:NOW)).zero?
|
32
|
+
end
|
33
|
+
|
34
|
+
def find(uuid:)
|
35
|
+
raw = dataset.where(uuid: uuid).first
|
36
|
+
raw[:data] = JSON.parse(raw[:data], symbolize_names: true)
|
37
|
+
raw[:error_details] = JSON.parse(raw[:error_details], symbolize_names: true) if raw[:error_details]
|
38
|
+
Event.wrap raw
|
39
|
+
end
|
40
|
+
|
41
|
+
def each_unprocessed
|
42
|
+
dataset.where(processed_at: nil).each do |raw|
|
43
|
+
raw[:data] = JSON.parse(raw[:data], symbolize_names: true)
|
44
|
+
raw[:error_details] = JSON.parse(raw[:error_details], symbolize_names: true) if raw[:error_details]
|
45
|
+
event = Event.wrap(raw)
|
46
|
+
yield(event)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'events_repo'
|
4
|
+
require 'luna_park/errors'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module CycloneLariat
|
8
|
+
class Middleware
|
9
|
+
def initialize(dataset: nil, errors_notifier: nil, message_notifier: nil, repo: EventsRepo)
|
10
|
+
@events_repo = repo.new(dataset) if dataset
|
11
|
+
@message_notifier = message_notifier
|
12
|
+
@errors_notifier = errors_notifier
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(_worker_instance, queue, _sqs_msg, body, &block)
|
16
|
+
log_received_message queue, body
|
17
|
+
|
18
|
+
catch_standard_error(queue, body) do
|
19
|
+
event = Event.wrap(JSON.parse(body[:Message]))
|
20
|
+
|
21
|
+
catch_business_error(event) do
|
22
|
+
store_in_dataset(event, &block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
attr_reader :errors_notifier, :message_notifier, :events_repo
|
30
|
+
|
31
|
+
def log_received_message(queue, body)
|
32
|
+
message_notifier&.info 'Receive message', queue: queue, aws_message_id: body[:MessageId], message: body[:Message]
|
33
|
+
end
|
34
|
+
|
35
|
+
def store_in_dataset(event)
|
36
|
+
return yield if events_repo.nil?
|
37
|
+
return true if events_repo.exists?(uuid: event.uuid)
|
38
|
+
|
39
|
+
events_repo.create(event)
|
40
|
+
yield
|
41
|
+
events_repo.processed! uuid: event.uuid
|
42
|
+
end
|
43
|
+
|
44
|
+
def catch_business_error(event)
|
45
|
+
yield
|
46
|
+
rescue LunaPark::Errors::Business => e
|
47
|
+
errors_notifier&.warning(e, event: event)
|
48
|
+
end
|
49
|
+
|
50
|
+
def catch_standard_error(queue, body)
|
51
|
+
yield
|
52
|
+
rescue StandardError => e
|
53
|
+
errors_notifier&.error(e, queue: queue, aws_message_id: body[:MessageId], message: body[:Message])
|
54
|
+
raise e
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/tasks/db.rake
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sequel'
|
4
|
+
require_relative '../../config/db'
|
5
|
+
|
6
|
+
namespace :db do
|
7
|
+
desc 'Create database'
|
8
|
+
task create: :config do
|
9
|
+
cmd = "PGPASSWORD=#{DB_CONF[:password]} createdb" \
|
10
|
+
" --username=#{DB_CONF[:username]}" \
|
11
|
+
" --host=#{DB_CONF[:host]}" \
|
12
|
+
" #{DB_CONF[:database]}"
|
13
|
+
puts "Database `#{DB_CONF[:database]}` successfully created" if system(cmd)
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Drop database'
|
17
|
+
task drop: :config do
|
18
|
+
cmd = "PGPASSWORD=#{DB_CONF[:password]} dropdb" \
|
19
|
+
" --username=#{DB_CONF[:username]}" \
|
20
|
+
" --host=#{DB_CONF[:host]}" \
|
21
|
+
" #{DB_CONF[:database]}"
|
22
|
+
puts "Database `#{DB_CONF[:database]}` successfully dropped" if system(cmd)
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Apply migrations'
|
26
|
+
task :migrate, [:version] => :config do |_, args|
|
27
|
+
require 'logger'
|
28
|
+
require 'sequel/core'
|
29
|
+
|
30
|
+
Sequel.extension :migration
|
31
|
+
version = args[:version] ? args[:version].to_i : nil
|
32
|
+
migrations_path = "#{__dir__}/../../db/migrate/"
|
33
|
+
|
34
|
+
Sequel.connect(**DB_CONF, logger: Logger.new($stdout)) do |db|
|
35
|
+
Sequel::Migrator.run(db, migrations_path, target: version)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
desc 'Database console'
|
40
|
+
task console: :config do
|
41
|
+
cmd = "PGPASSWORD=#{DB_CONF[:password]} psql" \
|
42
|
+
" --username=#{DB_CONF[:username]}" \
|
43
|
+
" --host=#{DB_CONF[:host]}" \
|
44
|
+
" --port=#{DB_CONF[:port]}" \
|
45
|
+
" #{DB_CONF[:database]}"
|
46
|
+
puts "Database `#{DB_CONF[:database]}` says 'bye-bye'" if system(cmd)
|
47
|
+
end
|
48
|
+
|
49
|
+
desc 'Reset database - drop, create, & migrate'
|
50
|
+
task :reset do
|
51
|
+
Rake::Task['db:drop'].invoke
|
52
|
+
Rake::Task['db:create'].invoke
|
53
|
+
Rake::Task['db:migrate'].invoke
|
54
|
+
end
|
55
|
+
end
|
metadata
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cyclone_lariat
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexander Kudrin
|
8
|
+
- Philip Sorokin
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2021-06-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: aws-sdk-sns
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: luna_park
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0.11'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0.11'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: bundler
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '2.1'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '2.1'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: byebug
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '11.1'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '11.1'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: database_cleaner-sequel
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '2.0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '2.0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: dry-validation
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '1.1'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '1.1'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: pg
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '1.2'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '1.2'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: pry
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0.13'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0.13'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: pry-byebug
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - "~>"
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '3.9'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - "~>"
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '3.9'
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: rake
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - "~>"
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '13.0'
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - "~>"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '13.0'
|
154
|
+
- !ruby/object:Gem::Dependency
|
155
|
+
name: rspec
|
156
|
+
requirement: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - "~>"
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '3.0'
|
161
|
+
type: :development
|
162
|
+
prerelease: false
|
163
|
+
version_requirements: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - "~>"
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '3.0'
|
168
|
+
- !ruby/object:Gem::Dependency
|
169
|
+
name: rubocop
|
170
|
+
requirement: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - "~>"
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0.87'
|
175
|
+
type: :development
|
176
|
+
prerelease: false
|
177
|
+
version_requirements: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - "~>"
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0.87'
|
182
|
+
- !ruby/object:Gem::Dependency
|
183
|
+
name: simplecov
|
184
|
+
requirement: !ruby/object:Gem::Requirement
|
185
|
+
requirements:
|
186
|
+
- - "~>"
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '0.18'
|
189
|
+
type: :development
|
190
|
+
prerelease: false
|
191
|
+
version_requirements: !ruby/object:Gem::Requirement
|
192
|
+
requirements:
|
193
|
+
- - "~>"
|
194
|
+
- !ruby/object:Gem::Version
|
195
|
+
version: '0.18'
|
196
|
+
- !ruby/object:Gem::Dependency
|
197
|
+
name: timecop
|
198
|
+
requirement: !ruby/object:Gem::Requirement
|
199
|
+
requirements:
|
200
|
+
- - "~>"
|
201
|
+
- !ruby/object:Gem::Version
|
202
|
+
version: '0.9'
|
203
|
+
type: :development
|
204
|
+
prerelease: false
|
205
|
+
version_requirements: !ruby/object:Gem::Requirement
|
206
|
+
requirements:
|
207
|
+
- - "~>"
|
208
|
+
- !ruby/object:Gem::Version
|
209
|
+
version: '0.9'
|
210
|
+
- !ruby/object:Gem::Dependency
|
211
|
+
name: webmock
|
212
|
+
requirement: !ruby/object:Gem::Requirement
|
213
|
+
requirements:
|
214
|
+
- - "~>"
|
215
|
+
- !ruby/object:Gem::Version
|
216
|
+
version: 3.7.0
|
217
|
+
type: :development
|
218
|
+
prerelease: false
|
219
|
+
version_requirements: !ruby/object:Gem::Requirement
|
220
|
+
requirements:
|
221
|
+
- - "~>"
|
222
|
+
- !ruby/object:Gem::Version
|
223
|
+
version: 3.7.0
|
224
|
+
- !ruby/object:Gem::Dependency
|
225
|
+
name: yard
|
226
|
+
requirement: !ruby/object:Gem::Requirement
|
227
|
+
requirements:
|
228
|
+
- - "~>"
|
229
|
+
- !ruby/object:Gem::Version
|
230
|
+
version: '0.9'
|
231
|
+
type: :development
|
232
|
+
prerelease: false
|
233
|
+
version_requirements: !ruby/object:Gem::Requirement
|
234
|
+
requirements:
|
235
|
+
- - "~>"
|
236
|
+
- !ruby/object:Gem::Version
|
237
|
+
version: '0.9'
|
238
|
+
description:
|
239
|
+
email:
|
240
|
+
- kudrin.alexander@gmail.com
|
241
|
+
executables: []
|
242
|
+
extensions: []
|
243
|
+
extra_rdoc_files: []
|
244
|
+
files:
|
245
|
+
- ".gitignore"
|
246
|
+
- ".rspec"
|
247
|
+
- ".rubocop.yml"
|
248
|
+
- ".ruby-gemset"
|
249
|
+
- ".ruby-version"
|
250
|
+
- CHANGELOG.md
|
251
|
+
- Gemfile
|
252
|
+
- Gemfile.lock
|
253
|
+
- README.md
|
254
|
+
- Rakefile
|
255
|
+
- config/db.example.rb
|
256
|
+
- config/db.rb
|
257
|
+
- cyclone_lariat.gemspec
|
258
|
+
- db/migrate/01_add_uuid_extensions.rb
|
259
|
+
- db/migrate/02_add_events.rb
|
260
|
+
- docs/_imgs/lariat.jpg
|
261
|
+
- lib/cyclone_lariat.rb
|
262
|
+
- lib/cyclone_lariat/client.rb
|
263
|
+
- lib/cyclone_lariat/errors.rb
|
264
|
+
- lib/cyclone_lariat/event.rb
|
265
|
+
- lib/cyclone_lariat/events_repo.rb
|
266
|
+
- lib/cyclone_lariat/middleware.rb
|
267
|
+
- lib/cyclone_lariat/version.rb
|
268
|
+
- lib/tasks/db.rake
|
269
|
+
homepage: https://am-team.github.io/cyclone_lariat/#/
|
270
|
+
licenses:
|
271
|
+
- MIT
|
272
|
+
metadata:
|
273
|
+
allowed_push_host: https://rubygems.org
|
274
|
+
yard.run: yri
|
275
|
+
post_install_message:
|
276
|
+
rdoc_options: []
|
277
|
+
require_paths:
|
278
|
+
- lib
|
279
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
280
|
+
requirements:
|
281
|
+
- - ">="
|
282
|
+
- !ruby/object:Gem::Version
|
283
|
+
version: 2.6.0
|
284
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
285
|
+
requirements:
|
286
|
+
- - ">="
|
287
|
+
- !ruby/object:Gem::Version
|
288
|
+
version: '0'
|
289
|
+
requirements: []
|
290
|
+
rubygems_version: 3.0.6
|
291
|
+
signing_key:
|
292
|
+
specification_version: 4
|
293
|
+
summary: Shoryuken middleware for LunaPark based application.
|
294
|
+
test_files: []
|