falcon 0.24.0 → 0.25.0

Sign up to get free protection for your applications and to get access to all the features.
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