falcon 0.24.0 → 0.25.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 504e6916fab8a0e117d92f5278a9b5fd9c882da9e390b32884db933af61f311d
4
- data.tar.gz: 1706310fa9fd8d820b005fad2fec24426828d92fdaeee5252e1f6e6fa0b6a50f
3
+ metadata.gz: 96425fc2402b25445c421f2d8dec1739c0f2b04701c6d47de48db140f0a55123
4
+ data.tar.gz: 3c6b31df8560bbf133873e9c37d9600204e2bd893b139c23a0587678c5cbe22e
5
5
  SHA512:
6
- metadata.gz: 5aedf3ada69a3df6e5c4be27617e9e4de163272f992ab1915568781e808991bfa4a0ba5e35051578195975dfc776afe704c5c6d810f0691e0335e5a7600380f5
7
- data.tar.gz: 816941e7cb925b12aedeb0b8cd171d4df3783eeb6b999bf73734b579fe3ae0545c7d9864ce20f1d28af69772be49ef88d44f3b2449189dfa534c56b16b42335d
6
+ metadata.gz: c3ce086375cceb639ba87947f286b66c1d53c2693717233bedb1f1fa2222b0b31b1747e3f39566592e508ad1f97545a5334bd5ff051c397fd7a93591a9c28dd5
7
+ data.tar.gz: 8bbf6a1e2717969ad54dadef79faa2566a3299069d97f675b697f1b0b5f8283419150f2430141bc6bdae09ea6272fb7a284aac44d131874c79aab3a5a24df5f2
data/README.md CHANGED
@@ -49,23 +49,26 @@ The `falcon serve` command has the following options for you to use:
49
49
  ```
50
50
  $ falcon --help
51
51
  falcon [--verbose | --quiet] [-h/--help] [-v/--version] <command>
52
- An asynchronous HTTP client/server toolset.
52
+ An asynchronous HTTP server.
53
53
 
54
54
  [--verbose | --quiet] Verbosity of output for debugging.
55
- [-h/--help] Print out help information.
55
+ [-h/--help] Print out help information.
56
56
  [-v/--version] Print out the application version.
57
57
  <command> One of: serve, virtual. Default: serve
58
58
 
59
- serve [-b/--bind <address>] [-p/--port <number>] [-h/--hostname <hostname>] [-c/--config <path>] [-n/--concurrency <count>] [--forked | --threaded]
59
+ serve [-b/--bind <address>] [-p/--port <number>] [-h/--hostname <hostname>] [-t/--timeout <duration>] [--reuse-port] [-c/--config <path>] [--forked | --threaded | --hybrid] [-n/--count <count>] [--forks <count>] [--threads <count>]
60
60
  Run an HTTP server.
61
61
 
62
- [-b/--bind <address>] Bind to the given hostname/address Default: https://localhost:9292
63
- [-p/--port <number>] Override the specified port
64
- [-h/--hostname <hostname>] Specify the hostname which would be used for certificates, etc.
65
- [-c/--config <path>] Rackup configuration file to load Default: config.ru
66
- [-n/--concurrency <count>] Number of processes to start Default: 8
67
- [--forked | --threaded] Select a specific concurrency model Default: forked
68
- ```
62
+ [-b/--bind <address>] Bind to the given hostname/address Default: https://localhost:9292
63
+ [-p/--port <number>] Override the specified port
64
+ [-h/--hostname <hostname>] Specify the hostname which would be used for certificates, etc.
65
+ [-t/--timeout <duration>] Specify the maximum time to wait for blocking operations. Default: 60
66
+ [--reuse-port] Enable SO_REUSEPORT if possible. Default: false
67
+ [-c/--config <path>] Rackup configuration file to load Default: config.ru
68
+ [--forked | --threaded | --hybrid] Select a specific parallelism model Default: forked
69
+ [-n/--count <count>] Number of instances to start. Default: 8
70
+ [--forks <count>] Number of forks (hybrid only).
71
+ [--threads <count>] Number of threads (hybrid only). ```
69
72
 
70
73
  To run on a different port:
71
74
 
@@ -118,7 +121,7 @@ Falcon supports `rack.hijack` for HTTP/1.x connections. You can thus use [async-
118
121
 
119
122
  #### ActionCable
120
123
 
121
- The `rack.hijack` functionality is compatible with ActionCable. If you use the `async` adapter, you should run falcon in threaded mode, or in forked mode with `--concurrency 1`. Otherwise, your messaging system will be distributed over several processes with no IPC mechanism. You might like to try out [async-redis](https://github.com/socketry/async-redis) as an asynchronous message bus.
124
+ The `rack.hijack` functionality is compatible with ActionCable. If you use the `async` adapter, you should run falcon in threaded mode, or in forked mode with `--count 1`. Otherwise, your messaging system will be distributed over several processes with no IPC mechanism. You might like to try out [async-redis](https://github.com/socketry/async-redis) as an asynchronous message bus.
122
125
 
123
126
  ### Early Hints
124
127
 
@@ -21,7 +21,7 @@ use MyApp # Then, it will get to Sinatra.
21
21
  run lambda {|env| [404, {}, []]} # Bottom of the stack, give 404.
22
22
 
23
23
  # Start server like this:
24
- # falcon --verbose serve --threaded --concurrency 1 --bind http://localhost:9292
24
+ # falcon --verbose serve --threaded --count 1 --bind http://localhost:9292
25
25
 
26
26
  # Test server, e.g.:
27
27
  # time ab -n 64 -c 64 http://localhost:9292/
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency("async", "~> 1.13")
22
22
  spec.add_dependency("async-io", "~> 1.18")
23
23
  spec.add_dependency("async-http", "~> 0.38.0")
24
- spec.add_dependency("async-container", "~> 0.9.0")
24
+ spec.add_dependency("async-container", "~> 0.10.0")
25
25
 
26
26
  spec.add_dependency("rack", ">= 1.0")
27
27
 
@@ -200,7 +200,7 @@ module Falcon
200
200
 
201
201
  return make_response(request, status, headers, body)
202
202
  rescue => exception
203
- @logger.error "#{exception.class}: #{exception.message}\n\t#{$!.backtrace.join("\n\t")}"
203
+ @logger.error(self) {exception}
204
204
 
205
205
  return failure_response(exception)
206
206
  end
@@ -20,12 +20,15 @@
20
20
 
21
21
  require_relative 'output'
22
22
  require_relative '../version'
23
+ require_relative '../proxy'
23
24
 
24
25
  require 'time'
25
26
 
26
27
  module Falcon
27
28
  module Adapters
28
29
  class Response < Async::HTTP::Response
30
+ IGNORE_HEADERS = Set.new(Proxy::HOP_HEADERS)
31
+
29
32
  # Append a list of newline encoded headers.
30
33
  def self.wrap_headers(fields)
31
34
  headers = ::HTTP::Protocol::Headers.new
@@ -36,8 +39,12 @@ module Falcon
36
39
  # This is a quick fix, but perhaps it should be part of the protocol, because it IS valid for HTTP/1.
37
40
  key = key.downcase
38
41
 
39
- value.to_s.split("\n").each do |part|
40
- headers.add(key, part)
42
+ if IGNORE_HEADERS.include? key
43
+ Async.logger.warn("Ignoring protocol-level header: #{key}: #{value}!")
44
+ else
45
+ value.to_s.split("\n").each do |part|
46
+ headers.add(key, part)
47
+ end
41
48
  end
42
49
  end
43
50
 
@@ -33,7 +33,7 @@ module Falcon
33
33
  end
34
34
 
35
35
  class Top < Samovar::Command
36
- self.description = "An asynchronous HTTP client/server toolset."
36
+ self.description = "An asynchronous HTTP server."
37
37
 
38
38
  options do
39
39
  option '--verbose | --quiet', "Verbosity of output for debugging.", key: :logging
@@ -42,24 +42,28 @@ module Falcon
42
42
 
43
43
  option '-p/--port <number>', "Override the specified port", type: Integer
44
44
  option '-h/--hostname <hostname>', "Specify the hostname which would be used for certificates, etc."
45
- option '-t/--timeout <duration>', "Specify the maximum time to wait for blocking operations.", type: Float, default: 60
45
+ option '-t/--timeout <duration>', "Specify the maximum time to wait for blocking operations.", type: Float, default: 60*10
46
46
 
47
47
  option '--reuse-port', "Enable SO_REUSEPORT if possible.", default: false
48
48
 
49
49
  option '-c/--config <path>', "Rackup configuration file to load", default: 'config.ru'
50
- option '-n/--concurrency <count>', "Number of processes to start", default: Async::Container.hardware_concurrency, type: Integer
51
50
 
52
- option '--forked | --threaded', "Select a specific concurrency model", key: :container, default: :forked
51
+ option '--forked | --threaded | --hybrid', "Select a specific parallelism model", key: :container, default: :forked
52
+
53
+ option '-n/--count <count>', "Number of instances to start.", default: Async::Container.processor_count, type: Integer
54
+
55
+ option '--forks <count>', "Number of forks (hybrid only).", type: Integer
56
+ option '--threads <count>', "Number of threads (hybrid only).", type: Integer
53
57
  end
54
58
 
55
59
  def container_class
56
60
  case @options[:container]
57
61
  when :threaded
58
- require 'async/container/threaded'
59
62
  return Async::Container::Threaded
60
63
  when :forked
61
- require 'async/container/forked'
62
64
  return Async::Container::Forked
65
+ when :hybrid
66
+ return Async::Container::Hybrid
63
67
  end
64
68
  end
65
69
 
@@ -69,29 +73,27 @@ module Falcon
69
73
  return Server.middleware(rack_app, verbose: verbose), options
70
74
  end
71
75
 
72
- def endpoint_options
73
- # Oh, for Hash#slice(keys...)
76
+ def slice_options(*keys)
77
+ # TODO: Ruby 2.5 introduced Hash#slice
74
78
  options = {}
75
79
 
76
- if @options.key? :hostname
77
- options[:hostname] = @options[:hostname]
78
- end
79
-
80
- if @options.key? :port
81
- options[:port] = @options[:port]
82
- end
83
-
84
- if @options.key? :reuse_port
85
- options[:reuse_port] = @options[:reuse_port]
86
- end
87
-
88
- if duration = @options[:timeout] and !duration.zero?
89
- options[:timeout] = duration
80
+ keys.each do |key|
81
+ if @options.key?(key)
82
+ options[key] = @options[key]
83
+ end
90
84
  end
91
85
 
92
86
  return options
93
87
  end
94
88
 
89
+ def container_options
90
+ slice_options(:count, :forks, :threads)
91
+ end
92
+
93
+ def endpoint_options
94
+ slice_options(:hostname, :port, :reuse_port, :timeout)
95
+ end
96
+
95
97
  def client_endpoint
96
98
  Async::HTTP::URLEndpoint.parse(@options[:bind], **endpoint_options)
97
99
  end
@@ -109,22 +111,22 @@ module Falcon
109
111
  Async::IO::SharedEndpoint.bound(endpoint)
110
112
  end.wait
111
113
 
112
- Async.logger.info(endpoint) do
113
- "Falcon taking flight! Using #{container_class} with concurrency: #{@options[:concurrency]}"
114
+ Async.logger.info(endpoint) do |buffer|
115
+ buffer.puts "Falcon taking flight! Using #{container_class} #{container_options}"
116
+ buffer.puts "- To terminate: Ctrl-C or kill #{Process.pid}"
114
117
  end
115
118
 
116
119
  debug_trap = Async::IO::Trap.new(:USR1)
117
-
118
120
  debug_trap.ignore!
119
121
 
120
- if container_class.multiprocess?
121
- Async.logger.info "Full status: kill -USR1 #{-Process.pid}"
122
- end
122
+ container = container_class.new
123
123
 
124
- container_class.new(concurrency: @options[:concurrency], name: "Falcon Server") do |task, instance|
124
+ container.run(name: "Falcon Server", restart: true, **container_options) do |task, instance|
125
125
  task.async do
126
126
  if debug_trap.install!
127
- Async.logger.info "Per-process status: kill -USR1 #{Process.pid}"
127
+ Async.logger.info(instance) do
128
+ "- Per-process status: kill -USR1 #{Process.pid}"
129
+ end
128
130
  end
129
131
 
130
132
  debug_trap.trap do
@@ -140,6 +142,8 @@ module Falcon
140
142
 
141
143
  task.children.each(&:wait)
142
144
  end
145
+
146
+ return container
143
147
  end
144
148
 
145
149
  def invoke(parent)
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Falcon
22
- VERSION = "0.24.0"
22
+ VERSION = "0.25.0"
23
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: falcon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.24.0
4
+ version: 0.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-10 00:00:00.000000000 Z
11
+ date: 2019-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http-protocol
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.9.0
75
+ version: 0.10.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.9.0
82
+ version: 0.10.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rack
85
85
  requirement: !ruby/object:Gem::Requirement