doctor-strange 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +315 -0
- data/Rakefile +11 -0
- data/app/controllers/doctor_strange/health_controller.rb +47 -0
- data/app/views/doctor_strange/health/check.html.erb +54 -0
- data/config/routes.rb +5 -0
- data/lib/doctor-strange.rb +8 -0
- data/lib/doctor_strange/configuration.rb +44 -0
- data/lib/doctor_strange/engine.rb +5 -0
- data/lib/doctor_strange/monitor.rb +51 -0
- data/lib/doctor_strange/providers/base.rb +39 -0
- data/lib/doctor_strange/providers/cache.rb +26 -0
- data/lib/doctor_strange/providers/database.rb +16 -0
- data/lib/doctor_strange/providers/email.rb +49 -0
- data/lib/doctor_strange/providers/payment.rb +48 -0
- data/lib/doctor_strange/providers/redis.rb +77 -0
- data/lib/doctor_strange/providers/resque.rb +16 -0
- data/lib/doctor_strange/providers/sidekiq.rb +81 -0
- data/lib/doctor_strange/version.rb +5 -0
- metadata +402 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 782f2977af71550ceaaf9c022cb0ebe2a64c848a
|
4
|
+
data.tar.gz: 026347d2385308caf7fc6e94783c8cbcaa673622
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 38e0ca7bef140169251ad1ca321f8abdc286f6285e361582b10aa1158b551c6c1a170bd3ed7131d236335c0612a8dfb13a599b3b1e5e38dabeda867775fe4146
|
7
|
+
data.tar.gz: 4e263004f6940811be98d4d8cccf45121121d33b74cb933bff102cc3783592062c1a3bc5b54e77573e92078a563b2912c7f05257e2cad38c3195b37c3e8f31cf
|
data/README.md
ADDED
@@ -0,0 +1,315 @@
|
|
1
|
+
# Doctor Strange
|
2
|
+
|
3
|
+
[![BuildStatus](https://circleci.com/gh/SiliconJungles/doctor-strange.svg?style=svg)](https://circleci.com/gh/SiliconJungles/doctor-strange)
|
4
|
+
|
5
|
+
Monitoring various services (db, cache, sidekiq/resque, email, redis, payment, etc).
|
6
|
+
|
7
|
+
## Examples
|
8
|
+
|
9
|
+
### HTML Status Page
|
10
|
+
|
11
|
+
![alt example](/docs/screenshots/status-page.png "SiliconJungles Status Page")
|
12
|
+
|
13
|
+
### JSON Response
|
14
|
+
|
15
|
+
```bash
|
16
|
+
>> curl -s http://localhost:3000/check.json | json_pp
|
17
|
+
```
|
18
|
+
|
19
|
+
```json
|
20
|
+
{
|
21
|
+
"results": [{
|
22
|
+
"name": "Database",
|
23
|
+
"message": "",
|
24
|
+
"status": "OK"
|
25
|
+
}, {
|
26
|
+
"name": "Redis",
|
27
|
+
"message": "",
|
28
|
+
"status": "OK"
|
29
|
+
}, {
|
30
|
+
"name": "Sidekiq",
|
31
|
+
"message": "",
|
32
|
+
"status": "OK"
|
33
|
+
}, {
|
34
|
+
"name": "Email",
|
35
|
+
"message": "",
|
36
|
+
"status": "OK"
|
37
|
+
}, {
|
38
|
+
"name": "Payment",
|
39
|
+
"message": "",
|
40
|
+
"status": "OK"
|
41
|
+
}],
|
42
|
+
"status": "ok",
|
43
|
+
"timestamp": "2018-03-12 16:36:55 +0800"
|
44
|
+
}
|
45
|
+
```
|
46
|
+
|
47
|
+
### XML Response
|
48
|
+
|
49
|
+
```bash
|
50
|
+
>> curl -s http://localhost:3000/check.xml
|
51
|
+
```
|
52
|
+
|
53
|
+
```xml
|
54
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
55
|
+
<hash>
|
56
|
+
<results type="array">
|
57
|
+
<result>
|
58
|
+
<name>Database</name>
|
59
|
+
<message />
|
60
|
+
<status>OK</status>
|
61
|
+
</result>
|
62
|
+
<result>
|
63
|
+
<name>Redis</name>
|
64
|
+
<message />
|
65
|
+
<status>OK</status>
|
66
|
+
</result>
|
67
|
+
<result>
|
68
|
+
<name>Sidekiq</name>
|
69
|
+
<message />
|
70
|
+
<status>OK</status>
|
71
|
+
</result>
|
72
|
+
<result>
|
73
|
+
<name>Email</name>
|
74
|
+
<message />
|
75
|
+
<status>OK</status>
|
76
|
+
</result>
|
77
|
+
<result>
|
78
|
+
<name>Payment</name>
|
79
|
+
<message />
|
80
|
+
<status>OK</status>
|
81
|
+
</result>
|
82
|
+
</results>
|
83
|
+
<status type="symbol">ok</status>
|
84
|
+
<timestamp>2018-03-12 16:38:31 +0800</timestamp>
|
85
|
+
</hash>
|
86
|
+
```
|
87
|
+
|
88
|
+
## Setup
|
89
|
+
|
90
|
+
If you are using bundler add doctor-strange to your Gemfile:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
gem 'doctor-strange'
|
94
|
+
```
|
95
|
+
|
96
|
+
Then run:
|
97
|
+
|
98
|
+
```bash
|
99
|
+
$ bundle install
|
100
|
+
```
|
101
|
+
|
102
|
+
Otherwise install the gem:
|
103
|
+
|
104
|
+
```bash
|
105
|
+
$ gem install doctor-strange
|
106
|
+
```
|
107
|
+
|
108
|
+
## Usage
|
109
|
+
You can mount this inside your app routes by adding this to config/routes.rb:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
mount DoctorStrange::Engine, at: '/'
|
113
|
+
```
|
114
|
+
|
115
|
+
## Supported Service Providers
|
116
|
+
The following services are currently supported:
|
117
|
+
|
118
|
+
* DB
|
119
|
+
* Cache
|
120
|
+
* Redis
|
121
|
+
* Sidekiq
|
122
|
+
* Resque
|
123
|
+
* Stripe
|
124
|
+
* MailGun
|
125
|
+
|
126
|
+
## Configuration
|
127
|
+
|
128
|
+
### Adding AppName
|
129
|
+
|
130
|
+
The app name is `SiliconJungles` by default. You can change to your app name.
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
DoctorStrange.configure do |config|
|
134
|
+
config.app_name = "YOUR_APP_NAME"
|
135
|
+
end
|
136
|
+
```
|
137
|
+
|
138
|
+
### Adding Providers
|
139
|
+
By default, only the database check is enabled. You can add more service providers by explicitly enabling them via an initializer:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
DoctorStrange.configure do |config|
|
143
|
+
config.cache
|
144
|
+
config.redis
|
145
|
+
config.sidekiq
|
146
|
+
# etc
|
147
|
+
end
|
148
|
+
```
|
149
|
+
|
150
|
+
We believe that having the database check enabled by default is very important, but if you still want to disable it
|
151
|
+
(e.g., if you use a database that isn't covered by the check) - you can do that by calling the `no_database` method:
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
DoctorStrange.configure do |config|
|
155
|
+
config.no_database
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
### Provider Configuration
|
160
|
+
|
161
|
+
Some of the providers can also accept additional configuration:
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
# Sidekiq
|
165
|
+
DoctorStrange.configure do |config|
|
166
|
+
config.sidekiq.configure do |sidekiq_config|
|
167
|
+
sidekiq_config.latency = 3.hours
|
168
|
+
sidekiq_config.queue_size = 50
|
169
|
+
end
|
170
|
+
end
|
171
|
+
```
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
# Redis
|
175
|
+
DoctorStrange.configure do |config|
|
176
|
+
config.redis.configure do |redis_config|
|
177
|
+
redis_config.connection = Redis.current # use your custom redis connection
|
178
|
+
redis_config.url = 'redis://user:pass@example.redis.com:90210/' # or URL
|
179
|
+
redis_config.max_used_memory = 200 # Megabytes
|
180
|
+
end
|
181
|
+
end
|
182
|
+
```
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
# Email - MailGun by default
|
186
|
+
DoctorStrange.configure do |config|
|
187
|
+
config.email.configure do |email_config|
|
188
|
+
email_config.api_key = "abcd"
|
189
|
+
email_config.domain = "foo.bar"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
```
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
# Payment - Stripe by default
|
196
|
+
DoctorStrange.configure do |config|
|
197
|
+
config.payment.configure do |payment_config|
|
198
|
+
payment_config.api_key = "sk_live_xxxxx"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
```
|
202
|
+
|
203
|
+
The currently supported settings are:
|
204
|
+
|
205
|
+
#### Sidekiq
|
206
|
+
|
207
|
+
* `latency`: the latency (in seconds) of a queue (now - when the oldest job was enqueued) which is considered unhealthy (the default is 30 seconds, but larger processing queue should have a larger latency value).
|
208
|
+
* `queue_size`: the size (maximim) of a queue which is considered unhealthy (the default is 100).
|
209
|
+
|
210
|
+
#### Redis
|
211
|
+
|
212
|
+
* `url`: the url used to connect to your Redis instance - note, this is an optional configuration and will use the default connection if not specified
|
213
|
+
* `connection`: Use custom redis connection (e.g., `Redis.current`).
|
214
|
+
* `max_used_memory`: Set maximum expected memory usage of Redis in megabytes. Prevent memory leaks and keys overstore.
|
215
|
+
|
216
|
+
#### Email
|
217
|
+
|
218
|
+
- Default transaction email service for now is `MailGun`.
|
219
|
+
|
220
|
+
* `api_key`: the mail service api_key - this is a required value and will return unhealthy if not specified
|
221
|
+
* `domain`: the mail service domain value - this is a required value and will return unhealthy if not specified.
|
222
|
+
|
223
|
+
#### Payment
|
224
|
+
|
225
|
+
- Default payment service for now is `Stripe`.
|
226
|
+
|
227
|
+
* `api_key`: The Payment service's api_key - returns unhealthy if not specified or invalid.
|
228
|
+
|
229
|
+
### Adding a Custom Provider
|
230
|
+
It's also possible to add custom health check providers suited for your needs (of course, it's highly appreciated and encouraged if you'd contribute useful providers to the project).
|
231
|
+
|
232
|
+
In order to add a custom provider, you'd need to:
|
233
|
+
|
234
|
+
* Implement the `DoctorStrange::Providers::Base` class and its `check!` method (a check is considered as failed if it raises an exception):
|
235
|
+
|
236
|
+
```ruby
|
237
|
+
class CustomProvider < DoctorStrange::Providers::Base
|
238
|
+
def check!
|
239
|
+
raise 'Oh oh!'
|
240
|
+
end
|
241
|
+
end
|
242
|
+
```
|
243
|
+
* Add its class to the configuration:
|
244
|
+
|
245
|
+
```ruby
|
246
|
+
DoctorStrange.configure do |config|
|
247
|
+
config.add_custom_provider(CustomProvider)
|
248
|
+
end
|
249
|
+
```
|
250
|
+
|
251
|
+
### Adding a Custom Error Callback
|
252
|
+
If you need to perform any additional error handling (for example, for additional error reporting), you can configure a custom error callback:
|
253
|
+
|
254
|
+
```ruby
|
255
|
+
DoctorStrange.configure do |config|
|
256
|
+
config.error_callback = proc do |e|
|
257
|
+
logger.error "Health check failed with: #{e.message}"
|
258
|
+
|
259
|
+
Raven.capture_exception(e)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
```
|
263
|
+
|
264
|
+
### Adding Authentication Credentials
|
265
|
+
By default, the `/check` endpoint is not authenticated and is available to any user. You can authenticate using HTTP Basic Auth by providing authentication credentials:
|
266
|
+
|
267
|
+
```ruby
|
268
|
+
DoctorStrange.configure do |config|
|
269
|
+
config.basic_auth_credentials = {
|
270
|
+
username: 'SECRET_NAME',
|
271
|
+
password: 'Shhhhh!!!'
|
272
|
+
}
|
273
|
+
end
|
274
|
+
```
|
275
|
+
|
276
|
+
### Adding Environment Variables
|
277
|
+
By default, environment variables is `nil`, so if you'd want to include additional parameters in the results JSON, all you need is to provide a `Hash` with your custom environment variables:
|
278
|
+
|
279
|
+
```ruby
|
280
|
+
DoctorStrange.configure do |config|
|
281
|
+
config.environment_variables = {
|
282
|
+
build_number: 'BUILD_NUMBER',
|
283
|
+
git_sha: 'GIT_SHA'
|
284
|
+
}
|
285
|
+
end
|
286
|
+
```
|
287
|
+
|
288
|
+
## TODO
|
289
|
+
|
290
|
+
- [ ] Support another transaction Email services such as: SES, Mandrill by MailChimp, SendGird, AliCloud's DirectMail, etc.
|
291
|
+
|
292
|
+
- [ ] Support another payment services such as: Adyen, Braintree, etc.
|
293
|
+
|
294
|
+
## License
|
295
|
+
|
296
|
+
The MIT License (MIT)
|
297
|
+
|
298
|
+
Copyright (c) 2018
|
299
|
+
|
300
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
301
|
+
this software and associated documentation files (the "Software"), to deal in
|
302
|
+
the Software without restriction, including without limitation the rights to
|
303
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
304
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
305
|
+
subject to the following conditions:
|
306
|
+
|
307
|
+
The above copyright notice and this permission notice shall be included in all
|
308
|
+
copies or substantial portions of the Software.
|
309
|
+
|
310
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
311
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
312
|
+
FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
313
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
314
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
315
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module DoctorStrange
|
2
|
+
class HealthController < ActionController::Base
|
3
|
+
protect_from_forgery with: :exception
|
4
|
+
|
5
|
+
if Rails.version.starts_with? '3'
|
6
|
+
before_filter :authenticate_with_basic_auth
|
7
|
+
else
|
8
|
+
before_action :authenticate_with_basic_auth
|
9
|
+
end
|
10
|
+
|
11
|
+
def check
|
12
|
+
@statuses = statuses
|
13
|
+
@app_name = DoctorStrange.configuration.app_name
|
14
|
+
|
15
|
+
respond_to do |format|
|
16
|
+
format.html
|
17
|
+
format.json do
|
18
|
+
render json: statuses.to_json
|
19
|
+
end
|
20
|
+
format.xml do
|
21
|
+
render xml: statuses.to_xml
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def statuses
|
29
|
+
res = DoctorStrange.check(request: request)
|
30
|
+
res.merge(env_vars)
|
31
|
+
end
|
32
|
+
|
33
|
+
def env_vars
|
34
|
+
v = DoctorStrange.configuration.environment_variables || {}
|
35
|
+
v.empty? ? {} : { environment_variables: v }
|
36
|
+
end
|
37
|
+
|
38
|
+
def authenticate_with_basic_auth
|
39
|
+
return true unless DoctorStrange.configuration.basic_auth_credentials
|
40
|
+
|
41
|
+
credentials = DoctorStrange.configuration.basic_auth_credentials
|
42
|
+
authenticate_or_request_with_http_basic do |name, password|
|
43
|
+
name == credentials[:username] && password == credentials[:password]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= @app_name %>Status</title>
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
<meta name="description" content="<%= @app_name %> Status">
|
8
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css">
|
9
|
+
</head>
|
10
|
+
|
11
|
+
<body>
|
12
|
+
<div class="container">
|
13
|
+
<h1 class="text-center"><%= @app_name %> Status Page</h1>
|
14
|
+
<table class="table table-hover table-bordered">
|
15
|
+
<thead>
|
16
|
+
<tr>
|
17
|
+
<th scope="col">#</th>
|
18
|
+
<th scope="col">Service</th>
|
19
|
+
<th scope="col">Status</th>
|
20
|
+
</tr>
|
21
|
+
</thead>
|
22
|
+
<tbody>
|
23
|
+
<% @statuses[:results].each_with_index do |status, index| %>
|
24
|
+
<% class_name = status[:status].downcase == 'error' ? 'text-danger' : 'text-success' %>
|
25
|
+
<tr>
|
26
|
+
<th scope="row"><%= index + 1 %></th>
|
27
|
+
<td> <%= status[:name] %></td>
|
28
|
+
<td class="<%= class_name %>">
|
29
|
+
<p><%= status[:status] %></p>
|
30
|
+
<%= status[:message] %>
|
31
|
+
</td>
|
32
|
+
</tr>
|
33
|
+
<% end %>
|
34
|
+
</tbody>
|
35
|
+
</table>
|
36
|
+
|
37
|
+
|
38
|
+
<!-- <div class="statuses">
|
39
|
+
<h1><%= @app_name %> Status Page</h1>
|
40
|
+
<% @statuses[:results].each do |status| %>
|
41
|
+
<div class="status status-<%= status[:status].downcase %>">
|
42
|
+
<div class="status-heading">
|
43
|
+
<span class="name"><%= status[:name] %></span>
|
44
|
+
<span class="state"><%= status[:status] %></span>
|
45
|
+
</div>
|
46
|
+
<div class="message"><%= status[:message] %></div>
|
47
|
+
</div>
|
48
|
+
<% end %>
|
49
|
+
</div> -->
|
50
|
+
<div class="text-center">
|
51
|
+
Powered by <a href="https://github.com/SiliconJungles/doctor-strange.git" target="_blank">Doctor Strange - SiliconJungles Team</a>
|
52
|
+
</div>
|
53
|
+
</div>
|
54
|
+
</body>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module DoctorStrange
|
2
|
+
class Configuration
|
3
|
+
PROVIDERS = %i[cache database redis resque sidekiq email payment].freeze
|
4
|
+
|
5
|
+
DEFAULT_APP_NAME = "SiliconJungles".freeze
|
6
|
+
|
7
|
+
attr_accessor :error_callback, :basic_auth_credentials, :environment_variables, :app_name
|
8
|
+
attr_reader :providers
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
database
|
12
|
+
@app_name = DEFAULT_APP_NAME
|
13
|
+
end
|
14
|
+
|
15
|
+
def no_database
|
16
|
+
@providers.delete(DoctorStrange::Providers::Database)
|
17
|
+
end
|
18
|
+
|
19
|
+
PROVIDERS.each do |provider_name|
|
20
|
+
define_method provider_name do |&_block|
|
21
|
+
require "doctor_strange/providers/#{provider_name}"
|
22
|
+
|
23
|
+
add_provider("DoctorStrange::Providers::#{provider_name.capitalize}".constantize)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_custom_provider(custom_provider_class)
|
28
|
+
unless custom_provider_class < DoctorStrange::Providers::Base
|
29
|
+
raise ArgumentError, 'custom provider class must implement '\
|
30
|
+
'DoctorStrange::Providers::Base'
|
31
|
+
end
|
32
|
+
|
33
|
+
add_provider(custom_provider_class)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def add_provider(provider_class)
|
39
|
+
(@providers ||= Set.new) << provider_class
|
40
|
+
|
41
|
+
provider_class
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'doctor_strange/configuration'
|
2
|
+
|
3
|
+
module DoctorStrange
|
4
|
+
STATUSES = {
|
5
|
+
ok: 'OK',
|
6
|
+
error: 'ERROR'
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
extend self
|
10
|
+
|
11
|
+
attr_accessor :configuration
|
12
|
+
|
13
|
+
def configure
|
14
|
+
self.configuration ||= Configuration.new
|
15
|
+
|
16
|
+
yield configuration if block_given?
|
17
|
+
end
|
18
|
+
|
19
|
+
def check(request: nil)
|
20
|
+
results = configuration.providers.map { |provider| provider_result(provider, request) }
|
21
|
+
|
22
|
+
{
|
23
|
+
results: results,
|
24
|
+
status: results.all? { |res| res[:status] == STATUSES[:ok] } ? :ok : :service_unavailable,
|
25
|
+
timestamp: Time.now.to_s(:rfc2822)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def provider_result(provider, request)
|
32
|
+
monitor = provider.new(request: request)
|
33
|
+
monitor.check!
|
34
|
+
|
35
|
+
{
|
36
|
+
name: provider.provider_name,
|
37
|
+
message: '',
|
38
|
+
status: STATUSES[:ok]
|
39
|
+
}
|
40
|
+
rescue StandardError => e
|
41
|
+
configuration.error_callback.call(e) if configuration.error_callback
|
42
|
+
|
43
|
+
{
|
44
|
+
name: provider.provider_name,
|
45
|
+
message: e.message,
|
46
|
+
status: STATUSES[:error]
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
DoctorStrange.configure
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module DoctorStrange
|
2
|
+
module Providers
|
3
|
+
class Base
|
4
|
+
attr_reader :request
|
5
|
+
attr_accessor :configuration
|
6
|
+
|
7
|
+
def self.provider_name
|
8
|
+
@name ||= name.demodulize
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.configure
|
12
|
+
return unless configurable?
|
13
|
+
|
14
|
+
@global_configuration = configuration_class.new
|
15
|
+
|
16
|
+
yield @global_configuration if block_given?
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(request: nil)
|
20
|
+
@request = request
|
21
|
+
|
22
|
+
return unless self.class.configurable?
|
23
|
+
self.configuration = self.class.instance_variable_get('@global_configuration')
|
24
|
+
end
|
25
|
+
|
26
|
+
# @abstract
|
27
|
+
def check!
|
28
|
+
raise NotImplementedError
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.configurable?
|
32
|
+
configuration_class
|
33
|
+
end
|
34
|
+
|
35
|
+
# @abstract
|
36
|
+
def self.configuration_class; end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'doctor_strange/providers/base'
|
2
|
+
|
3
|
+
module DoctorStrange
|
4
|
+
module Providers
|
5
|
+
class CacheException < StandardError; end
|
6
|
+
|
7
|
+
class Cache < Base
|
8
|
+
def check!
|
9
|
+
time = Time.now.to_s
|
10
|
+
|
11
|
+
Rails.cache.write(key, time)
|
12
|
+
fetched = Rails.cache.read(key)
|
13
|
+
|
14
|
+
raise "different values (now: #{time}, fetched: #{fetched})" if fetched != time
|
15
|
+
rescue StandardError => e
|
16
|
+
raise CacheException, e.message
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def key
|
22
|
+
@key ||= ['health', request.try(:remote_ip)].join(':')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'doctor_strange/providers/base'
|
2
|
+
|
3
|
+
module DoctorStrange
|
4
|
+
module Providers
|
5
|
+
class DatabaseException < StandardError; end
|
6
|
+
|
7
|
+
class Database < Base
|
8
|
+
def check!
|
9
|
+
# Check connection to the DB:
|
10
|
+
ActiveRecord::Base.establish_connection # Establishes connection
|
11
|
+
ActiveRecord::Base.connection # Calls connection object
|
12
|
+
raise DatabaseException.new("Your database is not connected") unless ActiveRecord::Base.connected?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'doctor_strange/providers/base'
|
2
|
+
require 'mailgun'
|
3
|
+
|
4
|
+
module DoctorStrange
|
5
|
+
module Providers
|
6
|
+
class EmailException < StandardError; end
|
7
|
+
|
8
|
+
class Email < Base
|
9
|
+
class Configuration
|
10
|
+
DEFAULT_SERVICE_NAME = "MailGun".freeze
|
11
|
+
|
12
|
+
attr_accessor :api_key, :domain, :service_name
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@service_name = DEFAULT_SERVICE_NAME
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
private
|
21
|
+
|
22
|
+
def configuration_class
|
23
|
+
::DoctorStrange::Providers::Email::Configuration
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def check!
|
28
|
+
check_required_values!
|
29
|
+
check_communication!
|
30
|
+
rescue StandardError => e
|
31
|
+
raise EmailException, e.message
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def check_required_values!
|
37
|
+
raise "The api_key and domain are required" if configuration.api_key.empty? || configuration.domain.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_communication!
|
41
|
+
mg_client = Mailgun::Client.new(configuration.api_key)
|
42
|
+
domainer = Mailgun::Domains.new(mg_client)
|
43
|
+
domainer.list.pluck("name").include? configuration.domain
|
44
|
+
rescue Mailgun::CommunicationError
|
45
|
+
raise "Cannot communicate to Mailgun"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'doctor_strange/providers/base'
|
2
|
+
require 'stripe'
|
3
|
+
|
4
|
+
module DoctorStrange
|
5
|
+
module Providers
|
6
|
+
class PaymentException < StandardError; end
|
7
|
+
|
8
|
+
class Payment < Base
|
9
|
+
class Configuration
|
10
|
+
DEFAULT_SERVICE_NAME = "Stripe".freeze
|
11
|
+
|
12
|
+
attr_accessor :api_key, :service_name
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@service_name = DEFAULT_SERVICE_NAME
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
private
|
21
|
+
|
22
|
+
def configuration_class
|
23
|
+
::DoctorStrange::Providers::Payment::Configuration
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def check!
|
28
|
+
check_required_values!
|
29
|
+
check_communication!
|
30
|
+
rescue Exception => e
|
31
|
+
raise PaymentException.new(e.message)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def check_required_values!
|
37
|
+
raise "The api_key is required" if configuration.api_key.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
def check_communication!
|
41
|
+
Stripe.api_key = configuration.api_key
|
42
|
+
Stripe::Customer.list(limit: 1)
|
43
|
+
rescue Stripe::AuthenticationError
|
44
|
+
raise "Invalid API Key provided"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'doctor_strange/providers/base'
|
2
|
+
|
3
|
+
module DoctorStrange
|
4
|
+
module Providers
|
5
|
+
class RedisException < StandardError; end
|
6
|
+
|
7
|
+
class Redis < Base
|
8
|
+
class Configuration
|
9
|
+
DEFAULT_URL = nil
|
10
|
+
|
11
|
+
attr_accessor :url, :connection, :max_used_memory
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@url = DEFAULT_URL
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
private
|
20
|
+
|
21
|
+
def configuration_class
|
22
|
+
::DoctorStrange::Providers::Redis::Configuration
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def check!
|
27
|
+
check_values!
|
28
|
+
check_max_used_memory!
|
29
|
+
rescue Exception => e
|
30
|
+
raise RedisException.new(e.message)
|
31
|
+
ensure
|
32
|
+
redis.close
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def check_values!
|
38
|
+
time = Time.now.to_s(:rfc2822)
|
39
|
+
|
40
|
+
redis.set(key, time)
|
41
|
+
fetched = redis.get(key)
|
42
|
+
|
43
|
+
raise "different values (now: #{time}, fetched: #{fetched})" if fetched != time
|
44
|
+
end
|
45
|
+
|
46
|
+
def check_max_used_memory!
|
47
|
+
return unless configuration.max_used_memory
|
48
|
+
return if used_memory_mb <= configuration.max_used_memory
|
49
|
+
|
50
|
+
raise "#{used_memory_mb}Mb memory using is higher than #{configuration.max_used_memory}Mb maximum expected"
|
51
|
+
end
|
52
|
+
|
53
|
+
def key
|
54
|
+
@key ||= ['health', request.try(:remote_ip)].join(':')
|
55
|
+
end
|
56
|
+
|
57
|
+
def redis
|
58
|
+
@redis =
|
59
|
+
if configuration.connection
|
60
|
+
configuration.connection
|
61
|
+
elsif configuration.url
|
62
|
+
::Redis.new(url: configuration.url)
|
63
|
+
else
|
64
|
+
::Redis.new
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def bytes_to_megabytes(bytes)
|
69
|
+
(bytes.to_f / 1024 / 1024).round
|
70
|
+
end
|
71
|
+
|
72
|
+
def used_memory_mb
|
73
|
+
bytes_to_megabytes(redis.info['used_memory'])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'doctor_strange/providers/base'
|
2
|
+
require 'resque'
|
3
|
+
|
4
|
+
module DoctorStrange
|
5
|
+
module Providers
|
6
|
+
class ResqueException < StandardError; end
|
7
|
+
|
8
|
+
class Resque < Base
|
9
|
+
def check!
|
10
|
+
::Resque.info
|
11
|
+
rescue Exception => e
|
12
|
+
raise ResqueException.new(e.message)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'doctor_strange/providers/base'
|
2
|
+
require 'sidekiq/api'
|
3
|
+
|
4
|
+
module DoctorStrange
|
5
|
+
module Providers
|
6
|
+
class SidekiqException < StandardError; end
|
7
|
+
|
8
|
+
class Sidekiq < Base
|
9
|
+
class Configuration
|
10
|
+
DEFAULT_LATENCY_TIMEOUT = 30
|
11
|
+
DEFAULT_QUEUES_SIZE = 100
|
12
|
+
|
13
|
+
attr_accessor :latency, :queue_size
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@latency = DEFAULT_LATENCY_TIMEOUT
|
17
|
+
@queue_size = DEFAULT_QUEUES_SIZE
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def check!
|
22
|
+
check_workers!
|
23
|
+
check_processes!
|
24
|
+
check_latency!
|
25
|
+
check_queue_size!
|
26
|
+
check_redis!
|
27
|
+
rescue Exception => e
|
28
|
+
raise SidekiqException, e.message
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
class << self
|
34
|
+
private
|
35
|
+
|
36
|
+
def configuration_class
|
37
|
+
::DoctorStrange::Providers::Sidekiq::Configuration
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def check_workers!
|
42
|
+
::Sidekiq::Workers.new.size
|
43
|
+
end
|
44
|
+
|
45
|
+
def check_processes!
|
46
|
+
sidekiq_stats = ::Sidekiq::Stats.new
|
47
|
+
return unless sidekiq_stats.processes_size.zero?
|
48
|
+
|
49
|
+
raise 'Sidekiq alive processes number is 0!'
|
50
|
+
end
|
51
|
+
|
52
|
+
def check_latency!
|
53
|
+
latency = queue.latency
|
54
|
+
|
55
|
+
return unless latency > configuration.latency
|
56
|
+
|
57
|
+
raise "latency #{latency} is greater than #{configuration.latency}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def check_queue_size!
|
61
|
+
size = queue.size
|
62
|
+
|
63
|
+
return unless size > configuration.queue_size
|
64
|
+
|
65
|
+
raise "queue size #{size} is greater than #{configuration.queue_size}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def check_redis!
|
69
|
+
if ::Sidekiq.respond_to?(:redis_info)
|
70
|
+
::Sidekiq.redis_info
|
71
|
+
else
|
72
|
+
::Sidekiq.redis(&:info)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private def queue
|
77
|
+
@queue ||= ::Sidekiq::Queue.new
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
metadata
ADDED
@@ -0,0 +1,402 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: doctor-strange
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- SiliconJungles
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-03-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: appraisal
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.2'
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 2.2.0
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '2.2'
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 2.2.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: capybara
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.18'
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 2.18.0
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '2.18'
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 2.18.0
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: capybara-screenshot
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - "~>"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '1.0'
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.0.18
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '1.0'
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: 1.0.18
|
87
|
+
- !ruby/object:Gem::Dependency
|
88
|
+
name: coveralls
|
89
|
+
requirement: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - "~>"
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0.8'
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.8.21
|
97
|
+
type: :development
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.8'
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: 0.8.21
|
107
|
+
- !ruby/object:Gem::Dependency
|
108
|
+
name: database_cleaner
|
109
|
+
requirement: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - "~>"
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '1.6'
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 1.6.2
|
117
|
+
type: :development
|
118
|
+
prerelease: false
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '1.6'
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 1.6.2
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: mailgun-ruby
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - "~>"
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '1.1'
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: 1.1.9
|
137
|
+
type: :development
|
138
|
+
prerelease: false
|
139
|
+
version_requirements: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - "~>"
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '1.1'
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: 1.1.9
|
147
|
+
- !ruby/object:Gem::Dependency
|
148
|
+
name: pry
|
149
|
+
requirement: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - "~>"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: 0.11.3
|
154
|
+
type: :development
|
155
|
+
prerelease: false
|
156
|
+
version_requirements: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - "~>"
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: 0.11.3
|
161
|
+
- !ruby/object:Gem::Dependency
|
162
|
+
name: rake
|
163
|
+
requirement: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - "~>"
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0.8'
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: 0.8.7
|
171
|
+
type: :development
|
172
|
+
prerelease: false
|
173
|
+
version_requirements: !ruby/object:Gem::Requirement
|
174
|
+
requirements:
|
175
|
+
- - "~>"
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '0.8'
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 0.8.7
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: rediska
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0.5'
|
188
|
+
- - ">="
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
version: 0.5.0
|
191
|
+
type: :development
|
192
|
+
prerelease: false
|
193
|
+
version_requirements: !ruby/object:Gem::Requirement
|
194
|
+
requirements:
|
195
|
+
- - "~>"
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '0.5'
|
198
|
+
- - ">="
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: 0.5.0
|
201
|
+
- !ruby/object:Gem::Dependency
|
202
|
+
name: resque
|
203
|
+
requirement: !ruby/object:Gem::Requirement
|
204
|
+
requirements:
|
205
|
+
- - "~>"
|
206
|
+
- !ruby/object:Gem::Version
|
207
|
+
version: '1.27'
|
208
|
+
- - ">="
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
version: 1.27.4
|
211
|
+
type: :development
|
212
|
+
prerelease: false
|
213
|
+
version_requirements: !ruby/object:Gem::Requirement
|
214
|
+
requirements:
|
215
|
+
- - "~>"
|
216
|
+
- !ruby/object:Gem::Version
|
217
|
+
version: '1.27'
|
218
|
+
- - ">="
|
219
|
+
- !ruby/object:Gem::Version
|
220
|
+
version: 1.27.4
|
221
|
+
- !ruby/object:Gem::Dependency
|
222
|
+
name: rspec-rails
|
223
|
+
requirement: !ruby/object:Gem::Requirement
|
224
|
+
requirements:
|
225
|
+
- - "~>"
|
226
|
+
- !ruby/object:Gem::Version
|
227
|
+
version: '3.7'
|
228
|
+
- - ">="
|
229
|
+
- !ruby/object:Gem::Version
|
230
|
+
version: 3.7.2
|
231
|
+
type: :development
|
232
|
+
prerelease: false
|
233
|
+
version_requirements: !ruby/object:Gem::Requirement
|
234
|
+
requirements:
|
235
|
+
- - "~>"
|
236
|
+
- !ruby/object:Gem::Version
|
237
|
+
version: '3.7'
|
238
|
+
- - ">="
|
239
|
+
- !ruby/object:Gem::Version
|
240
|
+
version: 3.7.2
|
241
|
+
- !ruby/object:Gem::Dependency
|
242
|
+
name: rspec_junit_formatter
|
243
|
+
requirement: !ruby/object:Gem::Requirement
|
244
|
+
requirements:
|
245
|
+
- - "~>"
|
246
|
+
- !ruby/object:Gem::Version
|
247
|
+
version: 0.3.0
|
248
|
+
type: :development
|
249
|
+
prerelease: false
|
250
|
+
version_requirements: !ruby/object:Gem::Requirement
|
251
|
+
requirements:
|
252
|
+
- - "~>"
|
253
|
+
- !ruby/object:Gem::Version
|
254
|
+
version: 0.3.0
|
255
|
+
- !ruby/object:Gem::Dependency
|
256
|
+
name: rubocop
|
257
|
+
requirement: !ruby/object:Gem::Requirement
|
258
|
+
requirements:
|
259
|
+
- - "~>"
|
260
|
+
- !ruby/object:Gem::Version
|
261
|
+
version: '0.5'
|
262
|
+
type: :development
|
263
|
+
prerelease: false
|
264
|
+
version_requirements: !ruby/object:Gem::Requirement
|
265
|
+
requirements:
|
266
|
+
- - "~>"
|
267
|
+
- !ruby/object:Gem::Version
|
268
|
+
version: '0.5'
|
269
|
+
- !ruby/object:Gem::Dependency
|
270
|
+
name: sidekiq
|
271
|
+
requirement: !ruby/object:Gem::Requirement
|
272
|
+
requirements:
|
273
|
+
- - "~>"
|
274
|
+
- !ruby/object:Gem::Version
|
275
|
+
version: '3.0'
|
276
|
+
type: :development
|
277
|
+
prerelease: false
|
278
|
+
version_requirements: !ruby/object:Gem::Requirement
|
279
|
+
requirements:
|
280
|
+
- - "~>"
|
281
|
+
- !ruby/object:Gem::Version
|
282
|
+
version: '3.0'
|
283
|
+
- !ruby/object:Gem::Dependency
|
284
|
+
name: spork
|
285
|
+
requirement: !ruby/object:Gem::Requirement
|
286
|
+
requirements:
|
287
|
+
- - "~>"
|
288
|
+
- !ruby/object:Gem::Version
|
289
|
+
version: 0.9.2
|
290
|
+
type: :development
|
291
|
+
prerelease: false
|
292
|
+
version_requirements: !ruby/object:Gem::Requirement
|
293
|
+
requirements:
|
294
|
+
- - "~>"
|
295
|
+
- !ruby/object:Gem::Version
|
296
|
+
version: 0.9.2
|
297
|
+
- !ruby/object:Gem::Dependency
|
298
|
+
name: sqlite3
|
299
|
+
requirement: !ruby/object:Gem::Requirement
|
300
|
+
requirements:
|
301
|
+
- - "~>"
|
302
|
+
- !ruby/object:Gem::Version
|
303
|
+
version: '1.3'
|
304
|
+
- - ">="
|
305
|
+
- !ruby/object:Gem::Version
|
306
|
+
version: 1.3.13
|
307
|
+
type: :development
|
308
|
+
prerelease: false
|
309
|
+
version_requirements: !ruby/object:Gem::Requirement
|
310
|
+
requirements:
|
311
|
+
- - "~>"
|
312
|
+
- !ruby/object:Gem::Version
|
313
|
+
version: '1.3'
|
314
|
+
- - ">="
|
315
|
+
- !ruby/object:Gem::Version
|
316
|
+
version: 1.3.13
|
317
|
+
- !ruby/object:Gem::Dependency
|
318
|
+
name: stripe
|
319
|
+
requirement: !ruby/object:Gem::Requirement
|
320
|
+
requirements:
|
321
|
+
- - "~>"
|
322
|
+
- !ruby/object:Gem::Version
|
323
|
+
version: '3.11'
|
324
|
+
- - ">="
|
325
|
+
- !ruby/object:Gem::Version
|
326
|
+
version: 3.11.0
|
327
|
+
type: :development
|
328
|
+
prerelease: false
|
329
|
+
version_requirements: !ruby/object:Gem::Requirement
|
330
|
+
requirements:
|
331
|
+
- - "~>"
|
332
|
+
- !ruby/object:Gem::Version
|
333
|
+
version: '3.11'
|
334
|
+
- - ">="
|
335
|
+
- !ruby/object:Gem::Version
|
336
|
+
version: 3.11.0
|
337
|
+
- !ruby/object:Gem::Dependency
|
338
|
+
name: timecop
|
339
|
+
requirement: !ruby/object:Gem::Requirement
|
340
|
+
requirements:
|
341
|
+
- - "~>"
|
342
|
+
- !ruby/object:Gem::Version
|
343
|
+
version: 0.9.1
|
344
|
+
type: :development
|
345
|
+
prerelease: false
|
346
|
+
version_requirements: !ruby/object:Gem::Requirement
|
347
|
+
requirements:
|
348
|
+
- - "~>"
|
349
|
+
- !ruby/object:Gem::Version
|
350
|
+
version: 0.9.1
|
351
|
+
description: A Rails plug-in, which checks various services (db, cache, sidekiq, redis,
|
352
|
+
stripe, mailgun, etc.).
|
353
|
+
email:
|
354
|
+
- developers@siliconjungles.com
|
355
|
+
executables: []
|
356
|
+
extensions: []
|
357
|
+
extra_rdoc_files: []
|
358
|
+
files:
|
359
|
+
- README.md
|
360
|
+
- Rakefile
|
361
|
+
- app/controllers/doctor_strange/health_controller.rb
|
362
|
+
- app/views/doctor_strange/health/check.html.erb
|
363
|
+
- config/routes.rb
|
364
|
+
- lib/doctor-strange.rb
|
365
|
+
- lib/doctor_strange/configuration.rb
|
366
|
+
- lib/doctor_strange/engine.rb
|
367
|
+
- lib/doctor_strange/monitor.rb
|
368
|
+
- lib/doctor_strange/providers/base.rb
|
369
|
+
- lib/doctor_strange/providers/cache.rb
|
370
|
+
- lib/doctor_strange/providers/database.rb
|
371
|
+
- lib/doctor_strange/providers/email.rb
|
372
|
+
- lib/doctor_strange/providers/payment.rb
|
373
|
+
- lib/doctor_strange/providers/redis.rb
|
374
|
+
- lib/doctor_strange/providers/resque.rb
|
375
|
+
- lib/doctor_strange/providers/sidekiq.rb
|
376
|
+
- lib/doctor_strange/version.rb
|
377
|
+
homepage: https://github.com/SiliconJungles/doctor-strange
|
378
|
+
licenses:
|
379
|
+
- MIT
|
380
|
+
metadata: {}
|
381
|
+
post_install_message:
|
382
|
+
rdoc_options: []
|
383
|
+
require_paths:
|
384
|
+
- lib
|
385
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
386
|
+
requirements:
|
387
|
+
- - ">="
|
388
|
+
- !ruby/object:Gem::Version
|
389
|
+
version: '0'
|
390
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
391
|
+
requirements:
|
392
|
+
- - ">="
|
393
|
+
- !ruby/object:Gem::Version
|
394
|
+
version: '0'
|
395
|
+
requirements: []
|
396
|
+
rubyforge_project:
|
397
|
+
rubygems_version: 2.6.13
|
398
|
+
signing_key:
|
399
|
+
specification_version: 4
|
400
|
+
summary: A Rails plug-in, which checks various services (db, cache, sidekiq, redis,
|
401
|
+
stripe, mailgun, etc.)
|
402
|
+
test_files: []
|