streamdal 0.0.1

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.
@@ -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: []