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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +72 -0
- data/Cargo.lock +192 -52
- data/README.md +131 -16
- data/exe/kino +0 -4
- data/ext/kino/Cargo.toml +4 -2
- data/ext/kino/src/access_log.rs +245 -0
- data/ext/kino/src/control.rs +701 -0
- data/ext/kino/src/cpus.rs +37 -0
- data/ext/kino/src/lib.rs +22 -1
- data/ext/kino/src/listen.rs +134 -0
- data/ext/kino/src/log.rs +144 -0
- data/ext/kino/src/mono.rs +26 -0
- data/ext/kino/src/queue.rs +11 -0
- data/ext/kino/src/registry.rs +158 -0
- data/ext/kino/src/request.rs +52 -2
- data/ext/kino/src/server.rs +229 -53
- data/ext/kino/src/style.rs +42 -39
- data/lib/kino/cli.rb +23 -9
- data/lib/kino/configuration.rb +77 -5
- data/lib/kino/errors_stream.rb +4 -3
- data/lib/kino/hook_fire.rb +22 -0
- data/lib/kino/log.rb +104 -0
- data/lib/kino/quarantine_monitor.rb +73 -0
- data/lib/kino/ractor_supervisor.rb +66 -16
- data/lib/kino/server.rb +201 -34
- data/lib/kino/templates/kino.rb.tt +62 -5
- data/lib/kino/version.rb +1 -1
- data/lib/kino/worker.rb +46 -30
- data/lib/kino/worker_hooks.rb +13 -0
- data/lib/kino.rb +14 -0
- data/lib/rackup/handler/kino.rb +88 -0
- data/sig/kino.rbs +71 -1
- metadata +26 -1
|
@@ -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:
|
|
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.
|
|
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:
|