kino 0.2.1 → 0.4.0

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,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rackup
4
+ module Handler
5
+ # The Rack handler: lets any host that speaks the rackup protocol boot
6
+ # Kino, which is what `rackup -s kino` and `rails server -u kino` do.
7
+ # Loaded on demand by Rackup::Handler.get(:kino), so Rackup itself is
8
+ # already defined here; Kino is required only when the host calls in.
9
+ module Kino
10
+ # Host option name => Kino setting plus the coercion it needs: rackup
11
+ # hands `-O NAME=VALUE` values (and its own -p) over as strings.
12
+ OPTION_MAP = {
13
+ Host: [:bind, ->(value) { value.to_s }],
14
+ Port: [:port, ->(value) { Integer(value) }],
15
+ Workers: [:workers, ->(value) { Integer(value) }],
16
+ Threads: [:threads, ->(value) { Integer(value) }],
17
+ Mode: [:mode, ->(value) { value.to_sym }]
18
+ }.freeze
19
+ private_constant :OPTION_MAP
20
+
21
+ # Boot a server for `app` and block until it shuts down, the way the
22
+ # `kino` executable does (banner, INT/TERM drain, stats on USR1).
23
+ #
24
+ # @param app [#call] the Rack application the host built
25
+ # @param options [Hash] the host's options (see {.server_options})
26
+ # @yield [server] the built, not yet started server, for hosts that
27
+ # want a handle on it
28
+ # @return [::Kino::Server] the stopped server, after shutdown
29
+ def self.run(app, **options)
30
+ require "kino"
31
+ server = ::Kino::Server.new(app, **server_options(options))
32
+ yield server if block_given?
33
+ server.run
34
+ end
35
+
36
+ # The `-O NAME=VALUE` options `rackup -s kino --help` lists (rackup
37
+ # shows its own -o/-p in place of Host and Port).
38
+ # @return [Hash{String => String}]
39
+ def self.valid_options
40
+ {
41
+ "Host=HOST" => "Address to bind (default: 127.0.0.1)",
42
+ "Port=PORT" => "Port to listen on (default: 9292)",
43
+ "Workers=COUNT" => "Workers: ractors in :ractor mode, thread groups in :threaded (default: one per CPU)",
44
+ "Threads=COUNT" => "Threads per worker (default: 1 in :ractor, 3 in :threaded)",
45
+ "Mode=MODE" => "auto | ractor | threaded (default: auto)",
46
+ "Config=PATH" => "Kino config file (default: kino.rb, then config/kino.rb)"
47
+ }
48
+ end
49
+
50
+ # Translate host options into {::Kino::Server#initialize} kwargs.
51
+ # Precedence: options the user typed > the config file > defaults the
52
+ # host supplied (rackup's and Rails' own Host and Port) > Kino's
53
+ # defaults. Hosts that say which options were typed pass
54
+ # `user_supplied_options`; when that list is absent every option
55
+ # counts as typed. Keys outside OPTION_MAP (the host's bookkeeping:
56
+ # environment, pid, config, ...) are ignored.
57
+ #
58
+ # @param options [Hash{Symbol => Object}]
59
+ # @return [Hash{Symbol => Object}]
60
+ def self.server_options(options)
61
+ require "kino"
62
+ options = options.dup
63
+ host_defaults = {}
64
+ if (typed = options.delete(:user_supplied_options))
65
+ (options.keys - typed).each { |key| host_defaults[key] = options.delete(key) }
66
+ end
67
+
68
+ config = ::Kino::Configuration.new
69
+ path = options.delete(:Config) || host_defaults.delete(:Config) || ::Kino::Configuration.default_path
70
+ config.load_file(path) if path
71
+ translate(host_defaults).each { |key, value| config.set(key, value) unless config.set?(key) }
72
+ config.merge!(translate(options))
73
+ config.set(:port, ::Kino::Configuration::DEFAULT_SERVING_PORT) unless config.set?(:port)
74
+ config.server_options
75
+ end
76
+
77
+ def self.translate(options)
78
+ options.filter_map do |key, value|
79
+ setting, coerce = OPTION_MAP[key]
80
+ [setting, coerce.call(value)] if setting
81
+ end.to_h
82
+ end
83
+ private_class_method :translate
84
+ end
85
+
86
+ register :kino, Kino
87
+ end
88
+ end
data/sig/kino.rbs CHANGED
@@ -20,13 +20,27 @@ module Kino
20
20
  # High-resolution sleep on the OS clock with the GVL released.
21
21
  def self.sleep: (Numeric seconds) -> nil
22
22
 
23
+ # CPUs this process may use (affinity mask and cgroup quota); never below 1.
24
+ def self.available_parallelism: () -> Integer
25
+
23
26
  class Server
24
27
  attr_reader port: Integer?
28
+ attr_reader control_port: Integer?
25
29
  attr_reader mode: Symbol
26
30
  attr_reader bind: String
27
31
 
28
32
  def tls?: () -> bool
29
33
 
34
+ # Whether the bind is a unix domain socket ("unix:///path/to.sock").
35
+ def unix?: () -> bool
36
+
37
+ # Where the server listens once started: http(s)://host:port or the
38
+ # unix:// socket path.
39
+ def url: () -> String
40
+
41
+ # Where the control plane listens once started, or nil when it is off.
42
+ def control_url: () -> String?
43
+
30
44
  # Settings precedence: explicit kwargs > config_file DSL > defaults.
31
45
  def initialize: (rack_app app, ?config_file: String?, **untyped options) -> void
32
46
 
@@ -41,9 +55,12 @@ module Kino
41
55
  # served, rejected, timeouts, respawns, lane_depths when lanes are on).
42
56
  def stats: () -> stats_hash
43
57
 
44
- # Production entry point: start, banner, signal traps, block until done.
58
+ # Production entry point: build the server and #run it.
45
59
  def self.run: (rack_app app, **untyped opts) -> Server
46
60
 
61
+ # Serve until shut down: start, banner, signal traps, block until done.
62
+ def run: () -> self
63
+
47
64
  # INT/TERM drain gracefully (second signal force-exits); USR1 prints stats.
48
65
  def self.trap_signals: (Server server) -> void
49
66
  end
@@ -52,6 +69,12 @@ module Kino
52
69
  DEFAULTS: Hash[Symbol, untyped]
53
70
  SETTINGS: Array[Symbol]
54
71
  SAMPLE_TEMPLATE: String
72
+ DEFAULT_PATHS: Array[String]
73
+ DEFAULT_SERVING_PORT: Integer
74
+
75
+ # The first of DEFAULT_PATHS (kino.rb, config/kino.rb) present in the
76
+ # working directory.
77
+ def self.default_path: () -> String?
55
78
 
56
79
  # The fully commented sample config (see `kino --init`).
57
80
  def self.sample: () -> String
@@ -98,11 +121,19 @@ module Kino
98
121
  def lanes: (boolish enabled) -> untyped
99
122
  def log_requests: (boolish enabled) -> untyped
100
123
  def on_error: (?^(Exception, Hash[String, untyped]) -> void handler) ?{ (Exception, Hash[String, untyped]) -> void } -> untyped
124
+ def after_boot: (?^() -> void handler) ?{ () -> void } -> untyped
125
+ def after_worker_boot: (?^(Integer) -> void handler) ?{ (Integer) -> void } -> untyped
126
+ def after_request_complete: (?^(Hash[String, untyped], Integer) -> void handler) ?{ (Hash[String, untyped], Integer) -> void } -> untyped
127
+ def on_worker_exit: (?^(Integer, Exception?) -> void handler) ?{ (Integer, Exception?) -> void } -> untyped
101
128
  def shutdown_timeout: (Numeric seconds) -> untyped
102
129
  def tokio_threads: (int count) -> untyped
103
130
  def tls: (cert: String, key: String) -> untyped
104
131
  def environment: (String | Symbol env) -> untyped
105
132
  def pidfile: (String path) -> untyped
133
+ def control_bind: (String addr) -> String
134
+ def control_token: (String token) -> String
135
+ def quarantine_timeout: (Numeric? seconds) -> untyped
136
+ def quarantine_max: (int count) -> untyped
106
137
  def rackup: (String path) -> untyped
107
138
  end
108
139
  end
@@ -159,6 +190,27 @@ module Kino
159
190
  def self.print_report: (rack_app app, ?io: IO) -> bool
160
191
  end
161
192
 
193
+ # Server log lines, `kino[<pid>] <source>: message`; safe inside worker
194
+ # ractors, so hooks may log through it.
195
+ module Log
196
+ FRAMES: Integer
197
+ WORKING_DIR: String
198
+
199
+ def self.info: (untyped message) -> void
200
+ def self.warn: (untyped message) -> void
201
+ def self.error: (untyped message) -> void
202
+
203
+ # The failed-request report: request line, error, and an app-first
204
+ # backtrace relative to the working directory.
205
+ def self.exception: (Exception error, Hash[String, untyped] env, ?status: Integer) -> void
206
+
207
+ # The `kino[<pid>] <source>:` tag.
208
+ def self.label: () -> String
209
+
210
+ # The ractor and/or thread name, or `main`.
211
+ def self.source: () -> String
212
+ end
213
+
162
214
  # A ::Logger writing through the native async sink.
163
215
  class Logger < ::Logger
164
216
  # path: a file (created/appended) or nil for stdout.
@@ -179,3 +231,21 @@ module Kino
179
231
  end
180
232
  end
181
233
  end
234
+
235
+ module Rackup
236
+ module Handler
237
+ # The Rack handler behind `rackup -s kino` and `rails server -u kino`.
238
+ module Kino
239
+ # Boot a server for app and block until shutdown; yields the built,
240
+ # not yet started server to hosts that want a handle on it.
241
+ def self.run: (::Kino::rack_app app, **untyped options) ?{ (::Kino::Server) -> void } -> ::Kino::Server
242
+
243
+ # The -O options rackup lists for this handler.
244
+ def self.valid_options: () -> Hash[String, String]
245
+
246
+ # Host options translated into Kino::Server kwargs, with precedence
247
+ # typed > config file > host defaults > Kino defaults.
248
+ def self.server_options: (Hash[Symbol, untyped] options) -> Hash[Symbol, untyped]
249
+ end
250
+ end
251
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kino
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yaroslav Markin
@@ -51,6 +51,20 @@ dependencies:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
53
  version: 0.9.128
54
+ - !ruby/object:Gem::Dependency
55
+ name: rackup
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.2'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '2.2'
54
68
  - !ruby/object:Gem::Dependency
55
69
  name: rake
56
70
  requirement: !ruby/object:Gem::Requirement
@@ -161,10 +175,16 @@ files:
161
175
  - ext/kino/Cargo.toml
162
176
  - ext/kino/build.rs
163
177
  - ext/kino/extconf.rb
178
+ - ext/kino/src/access_log.rs
179
+ - ext/kino/src/control.rs
180
+ - ext/kino/src/cpus.rs
164
181
  - ext/kino/src/env_strings.rs
165
182
  - ext/kino/src/gvl.rs
166
183
  - ext/kino/src/lib.rs
184
+ - ext/kino/src/listen.rs
185
+ - ext/kino/src/log.rs
167
186
  - ext/kino/src/logsink.rs
187
+ - ext/kino/src/mono.rs
168
188
  - ext/kino/src/pin.rs
169
189
  - ext/kino/src/queue.rs
170
190
  - ext/kino/src/registry.rs
@@ -180,15 +200,20 @@ files:
180
200
  - lib/kino/cli.rb
181
201
  - lib/kino/configuration.rb
182
202
  - lib/kino/errors_stream.rb
203
+ - lib/kino/hook_fire.rb
183
204
  - lib/kino/input.rb
205
+ - lib/kino/log.rb
184
206
  - lib/kino/logger.rb
185
207
  - lib/kino/null_input.rb
208
+ - lib/kino/quarantine_monitor.rb
186
209
  - lib/kino/ractor_supervisor.rb
187
210
  - lib/kino/server.rb
188
211
  - lib/kino/stream.rb
189
212
  - lib/kino/templates/kino.rb.tt
190
213
  - lib/kino/version.rb
191
214
  - lib/kino/worker.rb
215
+ - lib/kino/worker_hooks.rb
216
+ - lib/rackup/handler/kino.rb
192
217
  - sig/kino.rbs
193
218
  homepage: https://github.com/yaroslav/kino
194
219
  licenses: