Skip to content

Commit 865a24b

Browse files
authored
Merge pull request #74 from dblock/ping-worker
Added server ping worker.
2 parents 9458a50 + 2c13bc6 commit 865a24b

File tree

15 files changed

+307
-8
lines changed

15 files changed

+307
-8
lines changed

.rubocop_todo.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This configuration was generated by
22
# `rubocop --auto-gen-config`
3-
# on 2018-05-06 23:29:13 -0400 using RuboCop version 0.55.0.
3+
# on 2018-08-21 19:45:36 -0400 using RuboCop version 0.55.0.
44
# The point is for the user to remove these configuration records
55
# one by one as the offenses are removed from the code base.
66
# Note that changes in the inspected code, or installation of new

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
### Changelog
22

3-
#### 0.6.2 (Next)
3+
#### 0.7.0 (Next)
44

55
* [#60](https://github.com/slack-ruby/slack-ruby-bot-server/pull/60): Log caught Standard::Error backtrace at debug-level - [@alexagranov](https://github.com/alexagranov).
66
* [#65](https://github.com/slack-ruby/slack-ruby-bot-server/pull/65): Updated Capybara and selenium-webdriver - [@dblock](https://github.com/dblock).
77
* [#67](https://github.com/slack-ruby/slack-ruby-bot-server/pull/67): Only load the OTR::ActiveRecord::ConnectionManagement middleware when the OTR module is included. This module isn't needed when using Rails - [@darbyfrey](https://github.com/darbyfrey).
8+
* [#74](https://github.com/slack-ruby/slack-ruby-bot-server/pull/74): Added ping worker, will restart offline bots - [@dblock](https://github.com/dblock).
89
* Your contribution here.
910

1011
#### 0.6.1 (3/29/2017)

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,22 @@ SlackRubyBotServer.configure do |config|
152152
end
153153
```
154154

155+
#### Ping Worker
156+
157+
Each `SlackRubyBotServer::Server` instance will start a ping worker that will periodically check the online status of the bot via the Slack web [auth.test](https://api.slack.com/methods/auth.test) and [users.getPresence](https://api.slack.com/methods/users.getPresence) APIs, and will forcefully close the connection if the bot goes offline, causing an automatic reconnect.
158+
159+
You can configure the ping interval, number of retries before restart, and disable the ping worker entirely.
160+
161+
```ruby
162+
SlackRubyBotServer.configure do |config|
163+
config.ping = {
164+
enabled: true, # set to false to disable the ping worker
165+
ping_interval: 30, # interval in seconds
166+
retry_count: 3 # number of unsuccessful retries until a restart
167+
}
168+
end
169+
```
170+
155171
### Access Tokens
156172

157173
By default the implementation of [Team](lib/slack-ruby-bot-server/models/team) stores a `bot_access_token` that grants a certain amount of privileges to the bot user as described in [Slack OAuth Docs](https://api.slack.com/docs/oauth). You may not want a bot user at all, or may require different auth scopes, such as `users.profile:read` to access user profile information via `Slack::Web::Client#users_profile_get`. To obtain the non-bot access token make the following changes.

UPGRADING.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
11
Upgrading Slack-Ruby-Bot-Server
22
===============================
33

4+
### Upgrading to >= 0.7.0
5+
6+
#### New Ping Worker
7+
8+
Version 0.7.0 will automatically start a ping worker that checks for the bot's online status and forcefully terminate and restart disconnected bots. Set the ping `enabled` option to `false` to disable this behavior.
9+
10+
```ruby
11+
SlackRubyBotServer.configure do |config|
12+
config.ping = {
13+
enabled: false
14+
}
15+
end
16+
```
17+
18+
If you are currently using a custom ping worker as suggested in [slack-ruby-client#208](https://github.com/slack-ruby/slack-ruby-client/issues/208), delete it.
19+
20+
See [#74](https://github.com/slack-ruby/slack-ruby-bot-server/pull/74) for more information.
21+
422
### Upgrading to >= 0.6.0
523

624
#### Mongoid and ActiveRecord support

lib/slack-ruby-bot-server.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require 'grape-swagger'
44
require 'slack-ruby-bot'
55
require 'slack-ruby-bot-server/server'
6+
require 'slack-ruby-bot-server/ping'
67
require 'slack-ruby-bot-server/config'
78

89
require 'slack-ruby-bot-server/ext'

lib/slack-ruby-bot-server/api/middleware.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module Api
88
class Middleware
99
def self.logger
1010
@logger ||= begin
11-
$stdout.sync = true
11+
STDOUT.sync = true
1212
Logger.new(STDOUT)
1313
end
1414
end

lib/slack-ruby-bot-server/app.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def self.instance
1818

1919
def logger
2020
@logger ||= begin
21-
$stdout.sync = true
21+
STDOUT.sync = true
2222
Logger.new(STDOUT)
2323
end
2424
end

lib/slack-ruby-bot-server/config.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ module Config
33
extend self
44

55
attr_accessor :server_class
6+
attr_accessor :ping
67
attr_accessor :database_adapter
78

89
def reset!
10+
self.ping = nil
911
self.server_class = SlackRubyBotServer::Server
1012
self.database_adapter = if defined?(::Mongoid)
1113
:mongoid

lib/slack-ruby-bot-server/ping.rb

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
module SlackRubyBotServer
2+
class Ping
3+
include Celluloid
4+
5+
attr_reader :client
6+
attr_reader :options
7+
attr_reader :error_count
8+
9+
def initialize(client, options = {})
10+
@options = options
11+
@client = client
12+
@error_count = 0
13+
end
14+
15+
def start!
16+
every ping_interval do
17+
check!
18+
end
19+
end
20+
21+
private
22+
23+
def check!
24+
if online?
25+
@error_count = 0
26+
else
27+
down!
28+
end
29+
rescue StandardError => e
30+
case e.message
31+
when 'account_inactive', 'invalid_auth' then
32+
logger.warn "Error pinging team #{owner.id}: #{e.message}, terminating."
33+
terminate
34+
else
35+
logger.warn "Error pinging team #{owner.id}: #{e.message}."
36+
end
37+
end
38+
39+
def offline?
40+
!online?
41+
end
42+
43+
def online?
44+
presence.online
45+
end
46+
47+
def presence
48+
owner.ping![:presence]
49+
end
50+
51+
def down!
52+
logger.warn "DOWN: #{owner}, #{retries_left} #{retries_left == 1 ? 'retry' : 'retries'} left"
53+
@error_count += 1
54+
return if retries_left?
55+
restart!
56+
end
57+
58+
def restart!
59+
logger.warn "RESTART: #{owner}"
60+
driver.emit(:close, WebSocket::Driver::CloseEvent.new(1001, 'bot offline')) if driver
61+
terminate
62+
end
63+
64+
def ping_interval
65+
options[:ping_interval] || 60
66+
end
67+
68+
def retries_left?
69+
retries_left >= 0
70+
end
71+
72+
def retries_left
73+
retry_count - error_count
74+
end
75+
76+
def retry_count
77+
options[:retry_count] || 2
78+
end
79+
80+
def socket
81+
client.instance_variable_get(:@socket) if client
82+
end
83+
84+
def driver
85+
socket.instance_variable_get(:@driver) if socket
86+
end
87+
88+
def logger
89+
@logger ||= begin
90+
STDOUT.sync = true
91+
Logger.new(STDOUT)
92+
end
93+
end
94+
95+
def owner
96+
client.owner
97+
end
98+
end
99+
end

lib/slack-ruby-bot-server/server.rb

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,36 @@ class Server < SlackRubyBot::Server
77
def initialize(attrs = {})
88
attrs = attrs.dup
99
@team = attrs.delete(:team)
10+
@ping_options = attrs.delete(:ping) || {}
1011
raise 'Missing team' unless @team
1112
attrs[:token] = @team.token
1213
super(attrs)
13-
client.owner = @team
14+
open!
1415
end
1516

1617
def restart!(wait = 1)
1718
# when an integration is disabled, a live socket is closed, which causes the default behavior of the client to restart
1819
# it would keep retrying without checking for account_inactive or such, we want to restart via service which will disable an inactive team
1920
logger.info "#{team.name}: socket closed, restarting ..."
2021
SlackRubyBotServer::Service.instance.restart! team, self, wait
22+
open!
23+
end
24+
25+
private
26+
27+
attr_reader :ping_options
28+
29+
def create_ping
30+
return unless !ping_options.key?(:enabled) || ping_options[:enabled]
31+
SlackRubyBotServer::Ping.new(client, ping_options)
32+
end
33+
34+
def open!
2135
client.owner = team
36+
client.on :open do |_event|
37+
worker = create_ping
38+
worker.start! if worker
39+
end
2240
end
2341
end
2442
end

0 commit comments

Comments
 (0)