megaphone-client 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -8
- data/README.md +106 -15
- data/lib/megaphone/client.rb +29 -2
- data/lib/megaphone/client/errors.rb +14 -1
- data/lib/megaphone/client/event.rb +4 -0
- data/lib/megaphone/client/fluent_logger.rb +17 -3
- data/lib/megaphone/client/logger.rb +3 -2
- data/lib/megaphone/client/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15b75d53f469b5b1eb81174951801eb6b131957d
|
4
|
+
data.tar.gz: 72d170f64c4a6eb00f009411e21700ce238eee82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5510da93aa27aaa55aa0bfb6b4ea68cb11678f9c7424d89cd309cad42e87e220dc62b4a0bd2ba7d5925fe233a34f8fe07c8c2cfd427c8e97645b4f9508fdffcd
|
7
|
+
data.tar.gz: 2e6f71ac8caa1f13ab0bbf81351d6baf4056322d4e5cd4ffb85e8e3ca86a56d5ab8ba9a901eecc27a22a38d525d2b94bc3d7d219f9308285ae370d81059d7eba
|
data/CHANGELOG.md
CHANGED
@@ -5,11 +5,24 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and
|
6
6
|
this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [1.1.0] - 2018-01-30
|
9
|
+
|
10
|
+
### Added
|
11
|
+
|
12
|
+
* Add new `MegaphoneMessageDelayWarning` exception for transient errors
|
13
|
+
* Add `close` method to allow connection to Fluentd to be closed
|
14
|
+
* Support `buffer_overflow` callback to notify when messages have been lost ([documentation](../README.md#buffer-overflow-callback-handler))
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
|
18
|
+
* Update Fluentd Gem from 0.7.1 to 0.7.2
|
19
|
+
* Do not dump entire payload into exceptions; just stream/topic IDs
|
20
|
+
|
8
21
|
## [1.0.1] - 2017-09-18
|
9
22
|
|
10
23
|
### Fixed
|
11
24
|
|
12
|
-
|
25
|
+
* Output format to match the [stream-schema v2][stream-schema-v2].
|
13
26
|
|
14
27
|
[stream-schema-v2]: https://github.com/redbubble/megaphone-event-type-registry/blob/master/stream-schema-2.0.0.json
|
15
28
|
|
@@ -17,39 +30,40 @@ this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
|
|
17
30
|
|
18
31
|
### Changed
|
19
32
|
|
20
|
-
|
33
|
+
* The `Megaphone::Client` API is now stable!
|
21
34
|
|
22
35
|
## [0.3.0] - 2017-08-17
|
23
36
|
|
24
37
|
### Changed
|
25
38
|
|
26
|
-
|
39
|
+
* Signature of the `Megaphone::Client` constructor : now takes a host and a port as optional arguments and doesn't take the logger as an argument anymore.
|
27
40
|
|
28
41
|
## [0.2.0] - 2017-08-14
|
29
42
|
|
30
43
|
### Changed
|
31
44
|
|
32
|
-
|
45
|
+
* Signature of the `publish!` method: now takes a schema and a partition key as arguments
|
33
46
|
|
34
47
|
## [0.1.2] - 2017-08-04
|
35
48
|
|
36
49
|
### Fixed
|
37
50
|
|
38
|
-
|
51
|
+
* Removing unnecessary files from gemspec
|
39
52
|
|
40
53
|
## [0.1.1] - 2017-08-03
|
41
54
|
|
42
55
|
### Fixed
|
43
56
|
|
44
|
-
|
57
|
+
* Including files in gemspec
|
45
58
|
|
46
59
|
## 0.1.0 - 2017-08-03 [YANKED]
|
47
60
|
|
48
61
|
### Added
|
49
62
|
|
50
|
-
|
63
|
+
* Initial implementation of the `Megaphone::Client.publish!` method
|
51
64
|
|
52
|
-
[1.0
|
65
|
+
[1.1.0]: https://github.com/redbubble/megaphone-client-ruby/compare/v1.0.1...v1.1.0
|
66
|
+
[1.0.1]: https://github.com/redbubble/megaphone-client-ruby/compare/v1.0.0...v1.0.1
|
53
67
|
[1.0.0]: https://github.com/redbubble/megaphone-client-ruby/compare/v0.3.0...v1.0.0
|
54
68
|
[0.3.0]: https://github.com/redbubble/megaphone-client-ruby/compare/v0.2.0...v0.3.0
|
55
69
|
[0.2.0]: https://github.com/redbubble/megaphone-client-ruby/compare/v0.1.2...v0.2.0
|
data/README.md
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
Megaphone::Client
|
2
|
-
=================
|
1
|
+
# Megaphone::Client
|
3
2
|
|
4
3
|
[](https://buildkite.com/redbubble/megaphone-client-ruby)
|
5
4
|
[](https://badge.fury.io/rb/megaphone-client)
|
@@ -7,8 +6,7 @@ Megaphone::Client
|
|
7
6
|
|
8
7
|
Send events to [Megaphone](https://github.com/redbubble/Megaphone).
|
9
8
|
|
10
|
-
Getting Started
|
11
|
-
---------------
|
9
|
+
## Getting Started
|
12
10
|
|
13
11
|
Add the gem to your `Gemfile`:
|
14
12
|
|
@@ -18,18 +16,17 @@ Add the gem to your `Gemfile`:
|
|
18
16
|
gem 'megaphone-client', '~> 1.0' # see semver.org
|
19
17
|
```
|
20
18
|
|
21
|
-
Usage
|
22
|
-
-----
|
19
|
+
## Usage
|
23
20
|
|
24
21
|
In order to be as unobstrusive as possible, this client will append events to local files (e.g. `./work-updates.stream`) unless:
|
25
22
|
|
26
|
-
|
27
|
-
|
23
|
+
* the `MEGAPHONE_FLUENT_HOST` and `MEGAPHONE_FLUENT_PORT` environment variables are set.
|
24
|
+
* **or** the Fluentd host and port values are passed as arguments to the client's constructor
|
28
25
|
|
29
26
|
That behaviour ensures that unless you want to send events to the Megaphone [streams][stream], you do not need to [start Fluentd][megaphone-fluentd] at all.
|
30
27
|
|
31
|
-
|
32
|
-
|
28
|
+
[stream]: https://github.com/redbubble/megaphone#stream
|
29
|
+
[megaphone-fluentd]: https://github.com/redbubble/megaphone-fluentd-container
|
33
30
|
|
34
31
|
### Publishing events
|
35
32
|
|
@@ -54,19 +51,113 @@ payload = { url: 'https://www.redbubble.com/people/wytrab8/works/26039653-toadal
|
|
54
51
|
|
55
52
|
# Publish your event
|
56
53
|
client.publish!(topic, subtopic, schema, partition_key, payload)
|
54
|
+
|
55
|
+
# Note: the client will close the connection to Fluentd on exit, if you need to do it before that (unlikely), you can use Megaphone::Client#close method.
|
56
|
+
|
57
|
+
# See below for error handling instructions and examples.
|
57
58
|
```
|
58
59
|
|
59
|
-
|
60
|
-
|
60
|
+
## Error Handling
|
61
|
+
|
62
|
+
### Exceptions the client will raise
|
63
|
+
|
64
|
+
`publish!` can raise two exceptions if the underlying Fluentd
|
65
|
+
client library throws an error.
|
66
|
+
|
67
|
+
The most common is `MegaphoneMessageDelayWarning` which indicates
|
68
|
+
a transient failure occurred, but the message will probably be resent
|
69
|
+
later. See section on _[Internal buffering](#internal-buffering-upon-error)_ below for more details.
|
70
|
+
|
71
|
+
The second exception is `MegaphoneUnavailableError`, which is thrown
|
72
|
+
for all other errors. Note that these _may or may not_ also buffer
|
73
|
+
the message for later transmission. Unfortunately the underlying
|
74
|
+
client library does not make the distinction.
|
75
|
+
|
76
|
+
### Internal buffering upon error
|
77
|
+
|
78
|
+
Note that, in some cases, the client library will buffer failed messages
|
79
|
+
and attempt to resend them later. It will resend buffered messages in
|
80
|
+
the following cases:
|
81
|
+
|
82
|
+
* another message is sent
|
83
|
+
* the `close` method is called
|
84
|
+
* at exit (via an `at_exit` handler)
|
85
|
+
|
86
|
+
Applications that require fast handling of events should read the section
|
87
|
+
below on handling time-sensitive events and errors.
|
88
|
+
|
89
|
+
Because of this buffering, users of the library should not treat exceptions
|
90
|
+
as a definite reason to resend a message, as this may result in multiple
|
91
|
+
messages being eventually dispatched. However without in-depth knowledge
|
92
|
+
it can be hard to tell which exceptions are recoverable, and which indicate
|
93
|
+
some kind of catastrophic failure.
|
94
|
+
|
95
|
+
This author has confirmed that both connection failure and `ECONNRESET`
|
96
|
+
errors will result in buffering of messages.
|
97
|
+
|
98
|
+
If the internal buffer fills up, the buffer overflow handler will be called.
|
99
|
+
|
100
|
+
At exit, or when `client.close` is called, the buffer will be flushed.
|
101
|
+
If it cannot be flushed to the daemon, then the buffer overflow
|
102
|
+
handler will be called.
|
103
|
+
|
104
|
+
### Buffer overflow callback handler
|
105
|
+
|
106
|
+
Passing a lambda to the `:overflow_handler` will enable your application
|
107
|
+
to receive notifications of messages being lost. They can be lost in at
|
108
|
+
least two ways:
|
109
|
+
|
110
|
+
* Fluentd daemon has gone away, and internal client-side buffer exceeded
|
111
|
+
* process is shutting down, and fluent client library was unable to flush buffers
|
112
|
+
to the daemon.
|
113
|
+
|
114
|
+
Production applications [MUST][rfc2119] handle this case, and raise an alert, if their
|
115
|
+
messages are considered important.
|
116
|
+
|
117
|
+
[rfc2119]: https://tools.ietf.org/html/rfc2119
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
# Example usage:
|
121
|
+
my_handler = -> (*) {
|
122
|
+
Rollbar.error("Megaphone/fluent messages lost due to buffer overflow")
|
123
|
+
}
|
124
|
+
|
125
|
+
logger = Megaphone::Client.new({
|
126
|
+
origin: "my-app",
|
127
|
+
overflow_handler: my_handler
|
128
|
+
})
|
129
|
+
|
130
|
+
begin
|
131
|
+
logger.publish!(... event ...)
|
132
|
+
rescue Megaphone::Client::MegaphoneUnavailableError => e
|
133
|
+
Rollbar.warning("Megaphone client error", e)
|
134
|
+
rescue Megaphone::Client::MegaphoneMessageDelayWarning => e
|
135
|
+
Rollbar.info("Megaphone transient message delay", e)
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
### Handling time-sensitive events and errors
|
140
|
+
|
141
|
+
As long as an application is either short lived, or frequently sending messages,
|
142
|
+
then it will probably be fine with the usual behaviour, which is to flush
|
143
|
+
buffers at next send, or flush at exit.
|
144
|
+
|
145
|
+
Applications with time-sensitive, infrequent events, will need to find a
|
146
|
+
different strategy if errors have been raised during previous message publishing.
|
147
|
+
|
148
|
+
Unfortunately there is no means to do this with the underlying Ruby client
|
149
|
+
for Fluentd. It would require patches to the upstream code to expose a flush
|
150
|
+
method.
|
151
|
+
|
152
|
+
## Credits
|
61
153
|
|
62
154
|
[][redbubble]
|
63
155
|
|
64
156
|
Megaphone::Client is maintained and funded by [Redbubble][redbubble].
|
65
157
|
|
66
|
-
|
158
|
+
[redbubble]: https://www.redbubble.com
|
67
159
|
|
68
|
-
License
|
69
|
-
-------
|
160
|
+
## License
|
70
161
|
|
71
162
|
Megaphone::Client
|
72
163
|
Copyright (C) 2017 Redbubble
|
data/lib/megaphone/client.rb
CHANGED
@@ -8,18 +8,45 @@ module Megaphone
|
|
8
8
|
attr_reader :logger, :origin
|
9
9
|
private :logger, :origin
|
10
10
|
|
11
|
+
# Main entry point for apps using this library.
|
12
|
+
# Will default to environment for host and port settings, if not passed.
|
13
|
+
# Note that a missing callback_handler will result in a default handler
|
14
|
+
# being assigned if the FluentLogger is used.
|
11
15
|
def initialize(config)
|
12
16
|
@origin = config.fetch(:origin)
|
13
17
|
host = config.fetch(:host, ENV['MEGAPHONE_FLUENT_HOST'])
|
14
18
|
port = config.fetch(:port, ENV['MEGAPHONE_FLUENT_PORT'])
|
15
|
-
|
19
|
+
overflow_handler = config.fetch(:overflow_handler, nil)
|
20
|
+
@logger = Megaphone::Client::Logger.create(host, port, overflow_handler)
|
16
21
|
end
|
17
22
|
|
18
23
|
def publish!(topic, subtopic, schema, partition_key, payload)
|
19
24
|
event = Event.new(topic, subtopic, origin, schema, partition_key, payload)
|
20
25
|
unless logger.post(topic, event.to_hash)
|
21
|
-
|
26
|
+
if transient_error?(logger.last_error)
|
27
|
+
raise MegaphoneMessageDelayWarning.new(logger.last_error.message, event)
|
28
|
+
else
|
29
|
+
raise MegaphoneUnavailableError.new(logger.last_error.message, event)
|
30
|
+
end
|
22
31
|
end
|
23
32
|
end
|
33
|
+
|
34
|
+
def close
|
35
|
+
logger.close
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def transient_error?(err)
|
41
|
+
err_msg = err.message
|
42
|
+
if err_msg.include?("Connection reset by peer")
|
43
|
+
true
|
44
|
+
elsif err_msg.include?("Broken pipe")
|
45
|
+
true
|
46
|
+
else
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
24
51
|
end
|
25
52
|
end
|
@@ -9,7 +9,20 @@ module Megaphone
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def to_s
|
12
|
-
"#{@msg} -
|
12
|
+
"#{@msg} - An event could not be immediately published, but may be retried: #{@event.stream_id}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class MegaphoneMessageDelayWarning < StandardError
|
17
|
+
|
18
|
+
def initialize(msg, event)
|
19
|
+
super(msg)
|
20
|
+
@msg = msg
|
21
|
+
@event = event
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
"#{@msg} - Event delayed and will be reattempted: #{@event.stream_id}"
|
13
26
|
end
|
14
27
|
end
|
15
28
|
end
|
@@ -6,12 +6,26 @@ module Megaphone
|
|
6
6
|
class FluentLogger
|
7
7
|
extend Forwardable
|
8
8
|
|
9
|
-
def_delegators :@logger, :post, :last_error
|
9
|
+
def_delegators :@logger, :post, :last_error, :close
|
10
10
|
|
11
|
-
def initialize(host, port)
|
11
|
+
def initialize(host, port, overflow_handler = nil)
|
12
|
+
overflow_handler ||= default_overflow_handler
|
12
13
|
@logger = Fluent::Logger::FluentLogger.new('megaphone',
|
13
14
|
host: host,
|
14
|
-
port: port
|
15
|
+
port: port,
|
16
|
+
buffer_overflow_handler: overflow_handler
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
# A default overflow handler that just prints a warning message.
|
22
|
+
# Production applications should be passing in their own handlers,
|
23
|
+
# which should be alerting monitoring systems!
|
24
|
+
def default_overflow_handler
|
25
|
+
$stderr.puts("Megaphone::Client::FluentLogger - Production apps MUST override buffer overflow handler!")
|
26
|
+
-> (*) {
|
27
|
+
$stderr.puts("Buffer overflow in Megaphone/fluent logger - messages lost")
|
28
|
+
}
|
15
29
|
end
|
16
30
|
|
17
31
|
end
|
@@ -4,10 +4,11 @@ require 'megaphone/client/fluent_logger'
|
|
4
4
|
module Megaphone
|
5
5
|
class Client
|
6
6
|
class Logger
|
7
|
-
|
7
|
+
|
8
|
+
def self.create(host = nil, port = nil, overflow_handler = nil)
|
8
9
|
if !port.nil? && !port.empty? &&
|
9
10
|
!host.nil? && !host.empty?
|
10
|
-
return FluentLogger.new(host, port)
|
11
|
+
return FluentLogger.new(host, port, overflow_handler)
|
11
12
|
end
|
12
13
|
FileLogger.new
|
13
14
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: megaphone-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Redbubble
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2018-01-30 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: fluent-logger
|
@@ -94,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
94
94
|
version: '0'
|
95
95
|
requirements: []
|
96
96
|
rubyforge_project:
|
97
|
-
rubygems_version: 2.
|
97
|
+
rubygems_version: 2.4.5.1
|
98
98
|
signing_key:
|
99
99
|
specification_version: 4
|
100
100
|
summary: Send events to Megaphone.
|