hermann 0.11-x86-darwin-12 → 0.15-x86-darwin-12

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.
@@ -2,16 +2,17 @@
2
2
  * hermann_lib.h - Ruby wrapper for the librdkafka library
3
3
  *
4
4
  * Copyright (c) 2014 Stan Campbell
5
+ * Copyright (c) 2014 Lookout, Inc.
5
6
  * All rights reserved.
6
7
  *
7
8
  * Redistribution and use in source and binary forms, with or without
8
9
  * modification, are permitted provided that the following conditions are met:
9
10
  *
10
11
  * 1. Redistributions of source code must retain the above copyright notice,
11
- * this list of conditions and the following disclaimer.
12
+ * this list of conditions and the following disclaimer.
12
13
  * 2. Redistributions in binary form must reproduce the above copyright notice,
13
- * this list of conditions and the following disclaimer in the documentation
14
- * and/or other materials provided with the distribution.
14
+ * this list of conditions and the following disclaimer in the documentation
15
+ * and/or other materials provided with the distribution.
15
16
  *
16
17
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
18
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -42,8 +43,21 @@
42
43
 
43
44
  #include <librdkafka/rdkafka.h>
44
45
 
46
+ #ifdef TRACE
47
+ #define TRACER(...) do { \
48
+ fprintf(stderr, "%i:%s()> ", __LINE__, __PRETTY_FUNCTION__); \
49
+ fprintf(stderr, __VA_ARGS__); \
50
+ fflush(stderr); \
51
+ } while (0)
52
+ #else
53
+ #define TRACER(...) do { } while (0)
54
+ #endif
55
+
45
56
  // Holds the defined Ruby module for Hermann
46
- static VALUE m_hermann;
57
+ static VALUE hermann_module;
58
+
59
+ #define HERMANN_MAX_ERRSTR_LEN 512
60
+ #define HERMANN_MAX_TOPIC_LEN 512
47
61
 
48
62
  static int DEBUG = 0;
49
63
 
@@ -57,27 +71,38 @@ static enum {
57
71
  } output = OUTPUT_HEXDUMP;
58
72
 
59
73
  typedef struct HermannInstanceConfig {
74
+ char *topic;
60
75
 
61
- char* topic;
62
-
63
- /* Kafka configuration */
64
- rd_kafka_t *rk;
65
- rd_kafka_topic_t *rkt;
66
- char *brokers;
67
- int partition;
68
- rd_kafka_topic_conf_t *topic_conf;
69
- char errstr[512];
70
- rd_kafka_conf_t *conf;
71
- const char *debug;
72
- int64_t start_offset;
73
- int do_conf_dump;
76
+ /* Kafka configuration */
77
+ rd_kafka_t *rk;
78
+ rd_kafka_topic_t *rkt;
79
+ char *brokers;
80
+ int partition;
81
+ rd_kafka_topic_conf_t *topic_conf;
82
+ char errstr[512];
83
+ rd_kafka_conf_t *conf;
84
+ const char *debug;
85
+ int64_t start_offset;
86
+ int do_conf_dump;
74
87
 
75
- int run;
76
- int exit_eof;
77
- int quiet;
88
+ int run;
89
+ int exit_eof;
90
+ int quiet;
78
91
 
79
- int isInitialized;
92
+ int isInitialized;
93
+ int isConnected;
80
94
 
95
+ int isErrored;
96
+ char *error;
81
97
  } HermannInstanceConfig;
82
98
 
83
- #endif
99
+ typedef HermannInstanceConfig hermann_conf_t;
100
+
101
+ typedef struct {
102
+ /* Hermann::Lib::Producer */
103
+ hermann_conf_t *producer;
104
+ /* Hermann::Result */
105
+ VALUE result;
106
+ } hermann_push_ctx_t;
107
+
108
+ #endif
@@ -0,0 +1,19 @@
1
+ require 'hermann'
2
+ require 'hermann_lib'
3
+
4
+ module Hermann
5
+ class Consumer
6
+ attr_reader :topic, :brokers, :partition, :internal
7
+
8
+ def initialize(topic, brokers, partition)
9
+ @topic = topic
10
+ @brokers = brokers
11
+ @partition = partition
12
+ @internal = Hermann::Lib::Consumer.new(topic, brokers, partition)
13
+ end
14
+
15
+ def consume(&block)
16
+ @internal.consume(&block)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,8 @@
1
+
2
+ module Hermann
3
+ module Errors
4
+ # Error for connectivity problems with the Kafka brokers
5
+ class ConnectivityError; end;
6
+ end
7
+ end
8
+
@@ -0,0 +1,122 @@
1
+ require 'hermann'
2
+ require 'hermann/result'
3
+ require 'hermann_lib'
4
+
5
+ module Hermann
6
+ class Producer
7
+ attr_reader :topic, :brokers, :internal, :children
8
+
9
+ def initialize(topic, brokers)
10
+ @topic = topic
11
+ @brokers = brokers
12
+ @internal = Hermann::Lib::Producer.new(topic, brokers)
13
+ # We're tracking children so we can make sure that at Producer exit we
14
+ # make a reasonable attempt to clean up outstanding result objects
15
+ @children = []
16
+ end
17
+
18
+ # @return [Boolean] True if our underlying producer object thinks it's
19
+ # connected to a Kafka broker
20
+ def connected?
21
+ return @internal.connected?
22
+ end
23
+
24
+ # @return [Boolean] True if the underlying producer object has errored
25
+ def errored?
26
+ return @internal.errored?
27
+ end
28
+
29
+ def connect(timeout=0)
30
+ return @internal.connect(timeout * 1000)
31
+ end
32
+
33
+ # Push a value onto the Kafka topic passed to this +Producer+
34
+ #
35
+ # @param [Array] value An array of values to push, will push each one
36
+ # separately
37
+ # @param [Object] value A single object to push
38
+ # @return [Hermann::Result] A future-like object which will store the
39
+ # result from the broker
40
+ def push(value)
41
+ result = create_result
42
+
43
+ if value.kind_of? Array
44
+ return value.map { |e| self.push(e) }
45
+ else
46
+ @internal.push_single(value, result)
47
+ end
48
+
49
+ return result
50
+ end
51
+
52
+ # Create a +Hermann::Result+ that is tracked in the Producer's children
53
+ # array
54
+ #
55
+ # @return [Hermann::Result] A new, unused, result
56
+ def create_result
57
+ @children << Hermann::Result.new(self)
58
+ return @children.last
59
+ end
60
+
61
+ # Tick the underlying librdkafka reacter and clean up any unreaped but
62
+ # reapable children results
63
+ #
64
+ # @param [FixNum] timeout Seconds to block on the internal reactor
65
+ # @return [FixNum] Number of +Hermann::Result+ children reaped
66
+ def tick_reactor(timeout=0)
67
+ begin
68
+ execute_tick(rounded_timeout(timeout))
69
+ rescue StandardError => ex
70
+ @children.each do |child|
71
+ # Skip over any children that should already be reaped for other
72
+ # reasons
73
+ next if child.reap?
74
+ # Propagate errors to the remaining children
75
+ child.internal_set_error(ex)
76
+ end
77
+ end
78
+
79
+ # Reaping the children at this point will also reap any children marked
80
+ # as errored by an exception out of #execute_tick
81
+ return reap_children
82
+ end
83
+
84
+ # @return [FixNum] number of children reaped
85
+ def reap_children
86
+ # Filter all children who are no longer pending/fulfilled
87
+ total_children = @children.size
88
+ @children = @children.reject { |c| c.reap? }
89
+
90
+ return (total_children - children.size)
91
+ end
92
+
93
+
94
+ private
95
+
96
+ def rounded_timeout(timeout)
97
+ # Handle negative numbers, those can be zero
98
+ return 0 if (timeout < 0)
99
+ # Since we're going to sleep for each second, round any potential floats
100
+ # off
101
+ return timeout.round if timeout.kind_of?(Float)
102
+ return timeout
103
+ end
104
+
105
+ # Perform the actual reactor tick
106
+ # @raises [StandardError[ in case of underlying failures in librdkafka
107
+ def execute_tick(timeout)
108
+ if timeout == 0
109
+ @internal.tick(0)
110
+ else
111
+ (timeout * 2).times do
112
+ # We're going to Thread#sleep in Ruby to avoid a
113
+ # pthread_cond_timedwait(3) inside of librdkafka
114
+ events = @internal.tick(0)
115
+ # If we find events, break out early
116
+ break if events > 0
117
+ sleep 0.5
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,74 @@
1
+
2
+ module Hermann
3
+ class Result
4
+ attr_reader :reason, :state
5
+
6
+ STATES = [:pending,
7
+ :rejected,
8
+ :fulfilled,
9
+ :unfulfilled,
10
+ ].freeze
11
+
12
+ def initialize(producer)
13
+ @producer = producer
14
+ @reason = nil
15
+ @value = nil
16
+ @state = :unfulfilled
17
+ end
18
+
19
+ STATES.each do |state|
20
+ define_method("#{state}?".to_sym) do
21
+ return @state == state
22
+ end
23
+ end
24
+
25
+ # @return [Boolean] True if this child can be reaped
26
+ def reap?
27
+ return true if rejected? || fulfilled?
28
+ return false
29
+ end
30
+
31
+ # Access the value of the future
32
+ #
33
+ # @param [FixNum] timeout Seconds to wait on the underlying machinery for a
34
+ # result
35
+ # @return [NilClass] nil if no value could be received in the time alotted
36
+ # @return [Object]
37
+ def value(timeout=0)
38
+ @producer.tick_reactor(timeout)
39
+ return @value
40
+ end
41
+
42
+ # INTERNAL METHOD ONLY. Do not use
43
+ #
44
+ # This method will be invoked by the underlying extension to indicate set
45
+ # the actual value after a callback has completed
46
+ #
47
+ # @param [Object] value The actual resulting value
48
+ # @param [Boolean] is_error True if the result was errored for whatever
49
+ # reason
50
+ def internal_set_value(value, is_error)
51
+ @value = value
52
+
53
+ if is_error
54
+ puts "Hermann::Result#set_internal_value(#{value.class}:\"#{value}\", error?:#{is_error})"
55
+ @state = :rejected
56
+ else
57
+ @state = :fulfilled
58
+ end
59
+ end
60
+
61
+ # INTERNAL METHOD ONLY. Do not use
62
+ #
63
+ # This method will set our internal #reason with the details from the
64
+ # exception
65
+ #
66
+ # @param [Exception] exception
67
+ def internal_set_error(exception)
68
+ return if exception.nil?
69
+
70
+ @reason = exception
71
+ @state = :rejected
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'system_timer'
3
+ module Hermann
4
+ class Timeout
5
+ USE_SYSTEM_TIMER = true
6
+ end
7
+ end
8
+ rescue LoadError
9
+ require 'timeout'
10
+
11
+ if RUBY_VERSION == '1.8.7'
12
+ puts ">>> You are running on 1.8.7 without SystemTimer"
13
+ puts ">>> which means Hermann::Timeout will not work as expected"
14
+ end
15
+ module Hermann
16
+ class Timeout
17
+ USE_SYSTEM_TIMER = false
18
+ end
19
+ end
20
+ end
21
+
22
+ module Hermann
23
+ class Timeout
24
+ def self.system_timer?
25
+ Hermann::Timeout::USE_SYSTEM_TIMER
26
+ end
27
+
28
+ def self.timeout(seconds, klass=nil, &block)
29
+ if system_timer?
30
+ SystemTimer.timeout_after(seconds, klass, &block)
31
+ else
32
+ ::Timeout.timeout(seconds, klass, &block)
33
+ end
34
+ end
35
+ end
36
+ end
37
+
@@ -0,0 +1,3 @@
1
+ module Hermann
2
+ VERSION = '0.15'
3
+ end
data/lib/hermann.rb CHANGED
@@ -1 +1,2 @@
1
- require 'hermann_lib'
1
+ module Hermann
2
+ end
metadata CHANGED
@@ -1,40 +1,47 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hermann
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 21
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 11
9
- version: "0.11"
8
+ - 15
9
+ version: "0.15"
10
10
  platform: x86-darwin-12
11
11
  authors:
12
12
  - Stan Campbell
13
+ - R. Tyler Croy
13
14
  autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2014-05-29 00:00:00 Z
18
+ date: 2014-09-11 00:00:00 Z
18
19
  dependencies: []
19
20
 
20
- description: Ruby gem wrapper for the RdKafka C library
21
- email: stan.campbell3@gmail.com
21
+ description: Ruby gem wrapper for librdkafka
22
+ email:
23
+ - stan.campbell3@gmail.com
24
+ - rtyler.croy@lookout.com
22
25
  executables: []
23
26
 
24
27
  extensions:
25
- - ext/extconf.rb
28
+ - ext/hermann/extconf.rb
26
29
  extra_rdoc_files: []
27
30
 
28
31
  files:
29
32
  - Rakefile
30
- - ext/hermann_lib.h
31
- - ext/hermann_lib.c
32
- - ext/extconf.rb
33
- - bin/hermann
34
33
  - lib/hermann.rb
35
- - ext/hermann_lib.o
36
- - test/test_hermann.rb
37
- homepage: http://rubygems.org/gems/hermann
34
+ - lib/hermann/consumer.rb
35
+ - lib/hermann/errors.rb
36
+ - lib/hermann/producer.rb
37
+ - lib/hermann/result.rb
38
+ - lib/hermann/timeout.rb
39
+ - lib/hermann/version.rb
40
+ - ext/.ruby-version
41
+ - ext/hermann/extconf.rb
42
+ - ext/hermann/hermann_lib.c
43
+ - ext/hermann/hermann_lib.h
44
+ homepage: https://github.com/lookout/Hermann
38
45
  licenses:
39
46
  - MIT
40
47
  post_install_message:
@@ -42,7 +49,7 @@ rdoc_options: []
42
49
 
43
50
  require_paths:
44
51
  - lib
45
- - ext
52
+ - ext/hermann
46
53
  required_ruby_version: !ruby/object:Gem::Requirement
47
54
  none: false
48
55
  requirements:
@@ -67,6 +74,6 @@ rubyforge_project:
67
74
  rubygems_version: 1.8.25
68
75
  signing_key:
69
76
  specification_version: 3
70
- summary: The Kafka consumer is based on the librdkafka C library.
71
- test_files:
72
- - test/test_hermann.rb
77
+ summary: A Kafka consumer/producer gem based on the librdkafka C library.
78
+ test_files: []
79
+
data/bin/hermann DELETED
@@ -1,4 +0,0 @@
1
- #!ruby
2
-
3
- require 'hermann'
4
- puts "Placeholder..."