griffin 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grpc_kit'
4
+
5
+ require 'griffin/engine'
6
+ require 'griffin/server_config_builder'
7
+ require 'griffin/thread_pool'
8
+
9
+ module Griffin
10
+ class Server
11
+ DEFAULT_WORKER_SIZE = 10
12
+ DEFAULT_BACKLOG_SIZE = 1024
13
+
14
+ GRACEFUL_SHUTDOWN = '0'
15
+ FORCIBLE_SHUTDOWN = '1'
16
+
17
+ class << self
18
+ def run
19
+ c = config_builder.build
20
+ Griffin::Engine.start(c, cluster: Integer(c[:workers]) > 1)
21
+ end
22
+
23
+ def configure
24
+ yield(config_builder)
25
+ end
26
+
27
+ def config_builder
28
+ @config_builder ||= Griffin::ServerConfigBuilder.new
29
+ end
30
+ end
31
+
32
+ def initialize(worker_size: DEFAULT_WORKER_SIZE, **opts)
33
+ @worker_size = worker_size
34
+ @server = GrpcKit::Server.new
35
+ @opts = opts
36
+ @status = :run
37
+ @worker_id = 0
38
+ end
39
+
40
+ def handle(handler)
41
+ @server.handle(handler)
42
+ handler.class.rpc_descs.each do |path, _|
43
+ Griffin.logger.debug("Handle #{path}")
44
+ end
45
+ end
46
+
47
+ def before_run(worker_id = 0)
48
+ @worker_id = worker_id
49
+
50
+ # To separete fd with other forked process
51
+ @socks = []
52
+ @command, @signal = IO.pipe
53
+ @socks << @command
54
+ end
55
+
56
+ def run(sock, blocking: true)
57
+ @socks << sock
58
+
59
+ @thread_pool = Griffin::ThreadPool.new(@worker_size) do |conn|
60
+ @server.run(conn)
61
+ end
62
+
63
+ if blocking
64
+ handle_server
65
+ else
66
+ Thread.new { handle_server }
67
+ end
68
+ end
69
+
70
+ def shutdown(reason = GRACEFUL_SHUTDOWN)
71
+ @signal.write(reason)
72
+ end
73
+
74
+ private
75
+
76
+ def handle_server
77
+ while @status == :run
78
+ io = IO.select(@socks, [], [])
79
+
80
+ io[0].each do |sock|
81
+ if sock == @command
82
+ break if handle_command
83
+ end
84
+
85
+ begin
86
+ conn = sock.accept_nonblock
87
+ @thread_pool.schedule(conn[0])
88
+ rescue IO::WaitReadable, Errno::EINTR => e
89
+ Griffin.logger.debug("Error raised #{e}")
90
+ # nothing
91
+ end
92
+ end
93
+ end
94
+
95
+ @thread_pool.shutdown
96
+ # unless @sever.session_count == 0
97
+ # end
98
+
99
+ @command.close
100
+ @signal.close
101
+ end
102
+
103
+ def handle_command
104
+ case @command.read(1)
105
+ when FORCIBLE_SHUTDOWN
106
+ Griffin.logger.info("Shutting down sever(id=#{@worker_id}) forcibly...")
107
+
108
+ @status = :halt
109
+ @server.graceful_shutdown
110
+ true
111
+ when GRACEFUL_SHUTDOWN
112
+ Griffin.logger.info("Shutting down sever(id=#{@worker_id}) gracefully...")
113
+ @status = :stop
114
+ true
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Griffin
4
+ class ServerConfigBuilder
5
+ SERVERENGINE_PRIMITIVE_CONFIGS = %i[workers bind port log pid_path].freeze
6
+ SERVERENGINE_BLOCK_CONFIGS = %i[before_fork after_fork].freeze
7
+ # Users can't change these values
8
+ SERVERENGIEN_FIXED_CONFIGS = %i[daemonize worker_type worker_process_name].freeze
9
+ GRIFFIN_CONFIGS = %i[thread_pool].freeze
10
+ GRPC_CONFIGS = %i[services interceptors].freeze
11
+
12
+ ServerConfig = Struct.new(*(SERVERENGINE_PRIMITIVE_CONFIGS + SERVERENGINE_BLOCK_CONFIGS + SERVERENGIEN_FIXED_CONFIGS + GRIFFIN_CONFIGS + GRPC_CONFIGS)) do
13
+ def to_h
14
+ super.compact
15
+ end
16
+ end
17
+
18
+ DEFAULT_SERVER_CONFIG = {
19
+ worker_process_name: 'griffin worker',
20
+ daemonize: false,
21
+ log: '-', # STDOUT
22
+ worker_type: 'process',
23
+ workers: 1,
24
+ bind: '0.0.0.0',
25
+ port: 50051,
26
+ }.freeze
27
+
28
+ def initialize
29
+ @opts = DEFAULT_SERVER_CONFIG.dup
30
+ end
31
+
32
+ (SERVERENGINE_PRIMITIVE_CONFIGS + GRIFFIN_CONFIGS + [:interceptors]).each do |name|
33
+ define_method(name) do |value|
34
+ @opts[name] = value
35
+ end
36
+ end
37
+
38
+ SERVERENGINE_BLOCK_CONFIGS.each do |name|
39
+ define_method(name) do |&block|
40
+ @opts[name] = block
41
+ end
42
+ end
43
+
44
+ def services(*serv)
45
+ @opts[:services] = serv
46
+ end
47
+
48
+ def build
49
+ c = ServerConfig.new
50
+ @opts.each do |name, value|
51
+ c.send("#{name}=", value)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'griffin/counting_semaphore'
4
+
5
+ module Griffin
6
+ class ThreadPool
7
+ DEFAULT_POOL_SIZE = 20
8
+ DEFAULT_QUEUE_SIZE = 512
9
+
10
+ def initialize(pool_size = DEFAULT_POOL_SIZE, queue_size: DEFAULT_QUEUE_SIZE, &block)
11
+ @pool_size = pool_size
12
+ @queue_size = queue_size
13
+ @block = block
14
+ @shutdown = false
15
+ @semaphore = Griffin::CountingSemaphore.new(queue_size)
16
+ @tasks = Queue.new
17
+
18
+ @spawned = 0
19
+ @workers = []
20
+ @mutex = Mutex.new
21
+
22
+ @pool_size.times { spawn_thread }
23
+ end
24
+
25
+ def schedule(task, &block)
26
+ if task.nil?
27
+ return
28
+ end
29
+
30
+ if @shutdown
31
+ raise "scheduling new task isn't allowed during shutdown"
32
+ end
33
+
34
+ # TODO: blocking now..
35
+ @semaphore.wait
36
+ @tasks.push(block || task)
37
+
38
+ @mutex.synchronize do
39
+ if @spawned < @pool_size
40
+ spawn_thread
41
+ end
42
+ end
43
+ end
44
+
45
+ def shutdown
46
+ @shutdown = true
47
+ @pool_size.times { @tasks.push(nil) }
48
+ sleep 1 until @workers.empty?
49
+ end
50
+
51
+ private
52
+
53
+ def spawn_thread
54
+ @spawned += 1
55
+ worker = Thread.new(@spawned) do |i|
56
+ Thread.current.name = "Griffin worker thread #{i}"
57
+ Griffin.logger.debug("#{Thread.current.name} started")
58
+
59
+ loop do
60
+ if @shutdown
61
+ break
62
+ end
63
+
64
+ task = @tasks.pop
65
+ if task.nil?
66
+ break
67
+ end
68
+
69
+ begin
70
+ @block.call(task)
71
+ rescue Exception => e # rubocop:disable Lint/RescueException
72
+ Griffin.logger.error("An error occured on top level in worker #{Thread.current.name}: #{e.message} (#{e.class})\n #{Thread.current.backtrace.join("\n")} ")
73
+ ensure
74
+ @semaphore.signal
75
+ end
76
+ end
77
+
78
+ Griffin.logger.debug("worker thread #{Thread.current.name} is stopping")
79
+ @mutex.synchronize do
80
+ @spawned -= 1
81
+ @workers.delete(worker)
82
+ end
83
+ end
84
+
85
+ @workers.push(worker)
86
+ end
87
+ end
88
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Griffin
2
- VERSION = "0.1.0"
4
+ VERSION = '0.1.1'
3
5
  end
data/lib/griffin.rb CHANGED
@@ -1,5 +1,13 @@
1
- require "griffin/version"
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+ require 'grpc_kit'
5
+
6
+ require 'griffin/server'
7
+ require 'griffin/version'
2
8
 
3
9
  module Griffin
4
- # Your code goes here...
10
+ def self.logger
11
+ @logger ||= Logger.new(STDOUT, level: :info)
12
+ end
5
13
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: griffin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ganmacs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-10-17 00:00:00.000000000 Z
11
+ date: 2018-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,7 +52,63 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
- description: ''
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: connection_pool
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 2.2.2
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 2.2.2
83
+ - !ruby/object:Gem::Dependency
84
+ name: grpc_kit
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.1.5
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.1.5
97
+ - !ruby/object:Gem::Dependency
98
+ name: serverengine
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 2.0.7
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 2.0.7
111
+ description: Send and Receive RPCs from Ruby
56
112
  email:
57
113
  - ganmacs@gmail.com
58
114
  executables: []
@@ -61,16 +117,41 @@ extra_rdoc_files: []
61
117
  files:
62
118
  - ".gitignore"
63
119
  - ".rspec"
120
+ - ".rubocop.yml"
121
+ - ".ruby-version"
64
122
  - ".travis.yml"
65
- - CODE_OF_CONDUCT.md
66
123
  - Gemfile
67
124
  - LICENSE.txt
68
125
  - README.md
69
126
  - Rakefile
70
127
  - bin/console
71
128
  - bin/setup
129
+ - examples/helloworld/helloworld.proto
130
+ - examples/helloworld/helloworld_pb.rb
131
+ - examples/helloworld/helloworld_services_pb.rb
132
+ - examples/helloworld_client.rb
133
+ - examples/helloworld_server.rb
134
+ - examples/interceptors/client_logging_interceptor.rb
135
+ - examples/interceptors/server_logging_interceptor.rb
136
+ - examples/routeguide/routeguide.json
137
+ - examples/routeguide/routeguide.proto
138
+ - examples/routeguide/routeguide_pb.rb
139
+ - examples/routeguide/routeguide_services_pb.rb
140
+ - examples/routeguide_client.rb
141
+ - examples/routeguide_server.rb
72
142
  - griffin.gemspec
73
143
  - lib/griffin.rb
144
+ - lib/griffin/connection_pool/multi_timed_stack.rb
145
+ - lib/griffin/connection_pool/pool.rb
146
+ - lib/griffin/counting_semaphore.rb
147
+ - lib/griffin/engine.rb
148
+ - lib/griffin/engine/server.rb
149
+ - lib/griffin/engine/single.rb
150
+ - lib/griffin/engine/worker.rb
151
+ - lib/griffin/listener.rb
152
+ - lib/griffin/server.rb
153
+ - lib/griffin/server_config_builder.rb
154
+ - lib/griffin/thread_pool.rb
74
155
  - lib/griffin/version.rb
75
156
  homepage: https://github.com/ganmacs/griffin
76
157
  licenses:
@@ -92,8 +173,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
173
  version: '0'
93
174
  requirements: []
94
175
  rubyforge_project:
95
- rubygems_version: 2.6.14.1
176
+ rubygems_version: 2.7.6
96
177
  signing_key:
97
178
  specification_version: 4
98
- summary: ''
179
+ summary: Send and Receive RPCs from Ruby
99
180
  test_files: []
data/CODE_OF_CONDUCT.md DELETED
@@ -1,74 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- In the interest of fostering an open and welcoming environment, we as
6
- contributors and maintainers pledge to making participation in our project and
7
- our community a harassment-free experience for everyone, regardless of age, body
8
- size, disability, ethnicity, gender identity and expression, level of experience,
9
- nationality, personal appearance, race, religion, or sexual identity and
10
- orientation.
11
-
12
- ## Our Standards
13
-
14
- Examples of behavior that contributes to creating a positive environment
15
- include:
16
-
17
- * Using welcoming and inclusive language
18
- * Being respectful of differing viewpoints and experiences
19
- * Gracefully accepting constructive criticism
20
- * Focusing on what is best for the community
21
- * Showing empathy towards other community members
22
-
23
- Examples of unacceptable behavior by participants include:
24
-
25
- * The use of sexualized language or imagery and unwelcome sexual attention or
26
- advances
27
- * Trolling, insulting/derogatory comments, and personal or political attacks
28
- * Public or private harassment
29
- * Publishing others' private information, such as a physical or electronic
30
- address, without explicit permission
31
- * Other conduct which could reasonably be considered inappropriate in a
32
- professional setting
33
-
34
- ## Our Responsibilities
35
-
36
- Project maintainers are responsible for clarifying the standards of acceptable
37
- behavior and are expected to take appropriate and fair corrective action in
38
- response to any instances of unacceptable behavior.
39
-
40
- Project maintainers have the right and responsibility to remove, edit, or
41
- reject comments, commits, code, wiki edits, issues, and other contributions
42
- that are not aligned to this Code of Conduct, or to ban temporarily or
43
- permanently any contributor for other behaviors that they deem inappropriate,
44
- threatening, offensive, or harmful.
45
-
46
- ## Scope
47
-
48
- This Code of Conduct applies both within project spaces and in public spaces
49
- when an individual is representing the project or its community. Examples of
50
- representing a project or community include using an official project e-mail
51
- address, posting via an official social media account, or acting as an appointed
52
- representative at an online or offline event. Representation of a project may be
53
- further defined and clarified by project maintainers.
54
-
55
- ## Enforcement
56
-
57
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at TODO: Write your email address. All
59
- complaints will be reviewed and investigated and will result in a response that
60
- is deemed necessary and appropriate to the circumstances. The project team is
61
- obligated to maintain confidentiality with regard to the reporter of an incident.
62
- Further details of specific enforcement policies may be posted separately.
63
-
64
- Project maintainers who do not follow or enforce the Code of Conduct in good
65
- faith may face temporary or permanent repercussions as determined by other
66
- members of the project's leadership.
67
-
68
- ## Attribution
69
-
70
- This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
- available at [http://contributor-covenant.org/version/1/4][version]
72
-
73
- [homepage]: http://contributor-covenant.org
74
- [version]: http://contributor-covenant.org/version/1/4/