streamdal 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ require_relative 'spec_helper'
2
+
3
+ RSpec.describe "streamdal" do
4
+
5
+ end
data/lib/tail.rb ADDED
@@ -0,0 +1,97 @@
1
+ # TODO: implement token bucket limiter
2
+ require "bozos_buckets"
3
+
4
+ NUM_TAIL_WORKERS = 2
5
+ MIN_TAIL_RESPONSE_INTERVAL_MS = 100
6
+
7
+ module Streamdal
8
+ class Tail
9
+ attr_accessor :queue, :active, :request
10
+
11
+ def initialize(request, streamdal_url, auth_token, log, metrics, active = false)
12
+ @request = request
13
+ @streamdal_url = streamdal_url
14
+ @auth_token = auth_token
15
+ @logger = log
16
+ @metrics = metrics
17
+ @active = active
18
+ @last_msg = Time::at(0)
19
+ @queue = Queue.new
20
+ @workers = []
21
+
22
+ # Only use rate limiting if sample_options is set
23
+ unless request.sample_options.nil?
24
+ @limiter = BozosBuckets::Bucket.new(
25
+ initial_token_count: request.sample_options.sample_rate,
26
+ refill_rate: request.sample_options.sample_interval_seconds,
27
+ max_token_count: request.sample_options.sample_rate
28
+ )
29
+ end
30
+ end
31
+
32
+ def start_tail_workers
33
+ NUM_TAIL_WORKERS.times do |worker_id|
34
+ @workers << Thread.new { start_tail_worker(worker_id + 1) }
35
+ end
36
+
37
+ @active = true
38
+ end
39
+
40
+ def stop_tail
41
+ @active = false
42
+
43
+ sleep(1)
44
+
45
+ @workers.each do |worker|
46
+ if worker.alive?
47
+ worker.exit
48
+ end
49
+ end
50
+
51
+ end
52
+
53
+ def start_tail_worker(worker_id)
54
+ @logger.debug("Starting tail worker #{worker_id}")
55
+
56
+ # Each worker gets it's own gRPC connection
57
+ stub = Streamdal::Protos::Internal::Stub.new(@streamdal_url, :this_channel_is_insecure)
58
+
59
+ while @active
60
+ # If the queue is empty, sleep for a bit and loop again
61
+ if @queue.empty?
62
+ sleep(0.1)
63
+ next
64
+ end
65
+
66
+ if Time::now - @last_msg < MIN_TAIL_RESPONSE_INTERVAL_MS
67
+ sleep(MIN_TAIL_RESPONSE_INTERVAL_MS)
68
+ @metrics.incr(Metrics::CounterEntry.new(COUNTER_DROPPED_TAIL_MESSAGES, nil, {}, 1))
69
+ @logger.debug("Dropped tail message for '#{@request.id}' due to rate limiting")
70
+ next
71
+ end
72
+
73
+ unless stub.nil?
74
+ tail_response = @queue.pop(non_block = false)
75
+ @logger.debug("Sending tail request for '#{tail_response.tail_request_id}'")
76
+
77
+ begin
78
+ stub.send_tail([tail_response], metadata: { "auth-token" => @auth_token })
79
+ rescue => e
80
+ @logger.error("Error sending tail request: #{e}")
81
+ end
82
+ end
83
+ end
84
+
85
+ @logger.debug "Tail worker #{worker_id} exited"
86
+
87
+ end
88
+
89
+ def should_send
90
+ if @limiter.nil?
91
+ true
92
+ end
93
+
94
+ @limiter.use_tokens(1)
95
+ end
96
+ end
97
+ end
data/lib/tail_spec.rb ADDED
@@ -0,0 +1,5 @@
1
+ require_relative 'spec_helper'
2
+
3
+ RSpec.describe "Streamdal::Tail" do
4
+
5
+ end
data/lib/validation.rb ADDED
@@ -0,0 +1,88 @@
1
+ ##
2
+ # Validation mix-in module
3
+ require "steps/sp_steps_kv_pb"
4
+
5
+ module Validation
6
+ def validate_set_pipelines(cmd)
7
+ if cmd.nil?
8
+ raise "cmd is required"
9
+ end
10
+
11
+ if cmd.audience.nil?
12
+ raise "audience is required"
13
+ end
14
+
15
+ if cmd.set_pipelines.nil?
16
+ raise "set_pipelines command is required"
17
+ end
18
+
19
+ cmd.set_pipelines.each do |pipeline|
20
+ if pipeline.id == ""
21
+ raise "pipeline id is required"
22
+ end
23
+ end
24
+ end
25
+
26
+ def validate_kv_command(cmd)
27
+ if cmd.nil?
28
+ raise "cmd is required"
29
+ end
30
+
31
+ if cmd.kv.nil?
32
+ raise "kv command is required"
33
+ end
34
+ end
35
+
36
+ def validate_kv_instruction(inst)
37
+ if inst.nil?
38
+ raise "instruction is required"
39
+ end
40
+
41
+ if inst.id == ""
42
+ raise "instruction id is required"
43
+ end
44
+
45
+ if inst.action.nil?
46
+ raise "instruction action is required"
47
+ end
48
+
49
+ if inst.action == :KV_ACTION_UNSET
50
+ raise "instruction action is required"
51
+ end
52
+
53
+ if inst.object.nil? and inst.action != :KV_ACTION_DELETE_ALL
54
+ raise "instruction object is required"
55
+ end
56
+
57
+ validate_kv_object(inst.object)
58
+ end
59
+
60
+ def validate_kv_object(obj)
61
+ if obj.nil?
62
+ raise "object is required"
63
+ end
64
+
65
+ if obj.key == ""
66
+ raise "kv object key is required"
67
+ end
68
+
69
+ if obj.value == ""
70
+ raise "kv object value is required"
71
+ end
72
+
73
+ end
74
+
75
+ def validate_tail_request(cmd)
76
+ if cmd.nil?
77
+ raise "cmd is required"
78
+ end
79
+
80
+ if cmd.audience.nil?
81
+ raise "audience is required"
82
+ end
83
+
84
+ if cmd.tail.nil?
85
+ raise "tail is required"
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,77 @@
1
+ require 'rspec'
2
+ require 'sp_command_pb'
3
+ require 'sp_kv_pb'
4
+ require_relative 'spec_helper'
5
+ require_relative 'validation'
6
+
7
+ module Streamdal
8
+ class TestClient
9
+ include Validation
10
+ end
11
+ end
12
+
13
+ RSpec.describe "Validation" do
14
+ let(:validation) { Streamdal::TestClient.new }
15
+
16
+ context "#validate_kv_command" do
17
+ it "raises an error if cmd is nil" do
18
+ expect { validation.validate_kv_command(nil) }.to raise_error("cmd is required")
19
+ end
20
+
21
+ it "raises an error if cmd.kv is nil" do
22
+ cmd = Streamdal::Protos::Command.new
23
+ expect { validation.validate_kv_command(cmd) }.to raise_error("kv command is required")
24
+ end
25
+ end
26
+
27
+ context "#validate_kv_instruction" do
28
+ it "raises an error if inst is nil" do
29
+ expect { validation.validate_kv_instruction(nil) }.to raise_error("instruction is required")
30
+ end
31
+
32
+ it "raises an error if inst.id is empty" do
33
+ inst = Streamdal::Protos::KVInstruction.new
34
+ expect { validation.validate_kv_instruction(inst) }.to raise_error("instruction id is required")
35
+ end
36
+
37
+ it "raises an error if inst.action is KV_ACTION_UNSET" do
38
+ inst = Streamdal::Protos::KVInstruction.new(id: "id", action: 0)
39
+ expect { validation.validate_kv_instruction(inst) }.to raise_error("instruction action is required")
40
+ end
41
+
42
+ it "raises an error if inst.object is nil" do
43
+ inst = Streamdal::Protos::KVInstruction.new(id: "id", action: 1)
44
+ expect { validation.validate_kv_instruction(inst) }.to raise_error("instruction object is required")
45
+ end
46
+ end
47
+
48
+ context '#validate_kv_object' do
49
+ it "raises an error if obj is nil" do
50
+ expect { validation.validate_kv_object(nil) }.to raise_error("object is required")
51
+ end
52
+
53
+ it "raises an error if obj.key is empty" do
54
+ obj = Streamdal::Protos::KVObject.new
55
+ expect { validation.validate_kv_object(obj) }.to raise_error("kv object key is required")
56
+ end
57
+
58
+ it "raises an error if obj.value is empty" do
59
+ obj = Streamdal::Protos::KVObject.new(key: "key")
60
+ expect { validation.validate_kv_object(obj) }.to raise_error("kv object value is required")
61
+ end
62
+ end
63
+
64
+ context "#validate_tail_request" do
65
+ it "raises an error if cmd is nil" do
66
+ expect { validation.validate_tail_request(nil) }.to raise_error("cmd is required")
67
+ end
68
+
69
+ it "raises an error if cmd.tail_request is nil" do
70
+ cmd = Streamdal::Protos::Command.new
71
+ cmd.audience = Streamdal::Protos::Audience.new
72
+ cmd.tail = nil
73
+ expect { validation.validate_tail_request(cmd) }.to raise_error("tail is required")
74
+ end
75
+ end
76
+
77
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: streamdal
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mark Gregan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-05-03 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: mark@streamdal.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/audiences.rb
20
+ - lib/audiences_spec.rb
21
+ - lib/hostfunc.rb
22
+ - lib/hostfunc_spec.rb
23
+ - lib/kv.rb
24
+ - lib/kv_spec.rb
25
+ - lib/metrics.rb
26
+ - lib/metrics_spec.rb
27
+ - lib/schema.rb
28
+ - lib/schema_spec.rb
29
+ - lib/spec_helper.rb
30
+ - lib/streamdal.rb
31
+ - lib/streamdal_spec.rb
32
+ - lib/tail.rb
33
+ - lib/tail_spec.rb
34
+ - lib/validation.rb
35
+ - lib/validation_spec.rb
36
+ homepage: https://docs.streamdal.com
37
+ licenses:
38
+ - Apache-2.0
39
+ metadata: {}
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '='
47
+ - !ruby/object:Gem::Version
48
+ version: 0.0.1
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubygems_version: 3.3.5
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: Streamdal SDK
59
+ test_files: []