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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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..."