megaphone-client 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://badge.buildkite.com/9f4fdb370f5f295ee6bf3d68937b1be2d7cf9bf65b2c7b4213.svg?branch=master)](https://buildkite.com/redbubble/megaphone-client-ruby)
|
5
4
|
[![Gem Version](https://badge.fury.io/rb/megaphone-client.svg)](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
|
[![](doc/redbubble.png)][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.
|