1
1
#Learn-Rails-by-Reading-Source-Code
2
+ [ ![ LICENSE] ( https://img.shields.io/badge/license-Anti%20996-blue.svg )] ( https://github.com/996icu/996.ICU/blob/master/LICENSE )
3
+ [ ![ 996.icu] ( https://img.shields.io/badge/link-996.icu-red.svg )] ( https://996.icu )
2
4
##Table of Contents
3
5
4
6
* [ Part 0: Before reading Rails 5 source code] ( #part-0-before-reading-rails-5-source-code )
22
24
23
25
24
26
##Part 0: Before reading Rails 5 source code
25
- 1 ) I suggest you learn Rack[ http://rack.github.io/ ] ( http://rack.github.io/ ) first.
27
+ 1 ) I suggest youto learn Rack[ http://rack.github.io/ ] ( http://rack.github.io/ ) first.
26
28
27
- Inrack , an object with` call ` method is arack app.
29
+ InRack , an object with` call ` method is aRack app.
28
30
29
31
So what is the object with` call ` method in Rails? I will answer this question in Part 1.
30
32
@@ -37,7 +39,7 @@ So what is the object with `call` method in Rails? I will answer this question i
37
39
38
40
* How does Rails combine ActionController, ActionView and Routes together?
39
41
40
- * How doespuma, rack , Rails work together?
42
+ * How doesPuma, Rack , Rails work together?
41
43
42
44
* What's Puma's multiple threads?
43
45
@@ -55,7 +57,7 @@ module Rails
55
57
def perform
56
58
# ...
57
59
Rails ::Server .new (server_options).tapdo |server |
58
- # APP_PATH is '/Users/your_name /your_project/config/application'.
60
+ # APP_PATH is '/path/to /your_project/config/application'.
59
61
# require APP_PATH will create the 'Rails.application' object.
60
62
# Actually, 'Rails.application' is an instance of `YourProject::Application`.
61
63
# Rack server will start 'Rails.application'.
@@ -84,9 +86,9 @@ module Rails
84
86
end
85
87
end
86
88
```
87
- Arack server need to start with an` App ` object. The` App ` object should have a` call ` method.
89
+ ARack server need to start with an` App ` object. The` App ` object should have a` call ` method.
88
90
89
- ` config.ru ` is the conventional entry file forrack app. So let's look at it.
91
+ ` config.ru ` is the conventional entry file forRack app. So let's look at it.
90
92
``` ruby
91
93
# ./config.ru
92
94
require_relative ' config/environment'
@@ -264,9 +266,9 @@ Rack server will start `Rails.application` in the end.
264
266
265
267
` Rails.application ` is an important object in Rails.
266
268
267
- And you'll only have one` Rails.application ` in onepuma process.
269
+ And you'll only have one` Rails.application ` in onePuma process.
268
270
269
- Multiple threads in apuma process shares the` Rails.application ` .
271
+ Multiple threads in aPuma process shares the` Rails.application ` .
270
272
271
273
##Part 2: config
272
274
The first time we see the` config ` is in` ./config/application.rb ` .
382
384
```
383
385
384
386
###Puma
385
- When a request is made from client,puma will process the request in` Puma::Server#process_client ` .
387
+ When a request is made from client,Puma will process the request in` Puma::Server#process_client ` .
386
388
387
- If you want to know howpuma enter the method` Puma::Server#process_client ` , please read part 4 or just search 'process_client' in this document.
389
+ If you want to know howPuma enter the method` Puma::Server#process_client ` , please read part 4 or just search 'process_client' in this document.
388
390
389
391
``` ruby
390
392
# ./gems/puma-3.12.0/lib/puma/server.rb
@@ -447,7 +449,7 @@ module Puma
447
449
448
450
# Given the request +env+ from +client+ and a partial request body
449
451
# in +body+, finish reading the body if there is one and invoke
450
- # therack app. Then construct the response and write it back to
452
+ # theRack app. Then construct the response and write it back to
451
453
# +client+
452
454
#
453
455
def handle_request (req ,lines )
@@ -550,7 +552,7 @@ module Rails
550
552
puts " caller:#{ caller .inspect} "
551
553
552
554
# You may want to know when is the @app first time initialized.
553
- # It is initialized when 'config.ru' is load byrack server.
555
+ # It is initialized when 'config.ru' is load byRack server.
554
556
# Please search `Rack::Server#build_app_and_options_from_config` in this document for more information.
555
557
# When `Rails.application.initialize!` (in ./config/environment.rb) executed, @app is initialized.
556
558
@app || @app_build_lock .synchronize {# '@app_build_lock = Mutex.new', so multiple threads share one '@app'.
@@ -704,8 +706,8 @@ module ActionDispatch
704
706
end
705
707
706
708
def build (app )
707
- # klass israck middleware like : Rack::TempfileReaper, Rack::ETag, Rack::ConditionalGet or Rack::Head, etc.
708
- # It's typicalrack app to use these middlewares.
709
+ # klass isRack middleware like : Rack::TempfileReaper, Rack::ETag, Rack::ConditionalGet or Rack::Head, etc.
710
+ # It's typicalRack app to use these middlewares.
709
711
# See https://github.com/rack/rack-contrib/blob/master/lib/rack/contrib for more information.
710
712
klass.new (app,* args,& block)
711
713
end
730
732
# >
731
733
# >
732
734
```
733
- As we see in the Rack middleware stack, the lastone is
735
+ As we see in the Rack middleware stack, the last@ app is
734
736
735
737
` @app=#<ActionDispatch::Routing::RouteSet:0x00007fa1e594cbe8> `
736
738
``` ruby
@@ -1486,7 +1488,7 @@ module ActionView
1486
1488
end
1487
1489
1488
1490
```
1489
- After allrack apps called, user will get the response.
1491
+ After allRack apps called, user will get the response.
1490
1492
1491
1493
##Part 4: What does` $ rails server ` do?
1492
1494
@@ -1707,7 +1709,7 @@ module Rails
1707
1709
def perform
1708
1710
# ...
1709
1711
Rails ::Server .new (server_options).tapdo |server |
1710
- # APP_PATH is '/Users/your_name /your_project/config/application'.
1712
+ # APP_PATH is '/path/to /your_project/config/application'.
1711
1713
# require APP_PATH will create the 'Rails.application' object.
1712
1714
# 'Rails.application' is 'YourProject::Application.new'.
1713
1715
# Rack server will start 'Rails.application'.
@@ -1863,7 +1865,7 @@ module Puma
1863
1865
# with configuration in `config/puma.rb` or `config/puma/<env>.rb`.
1864
1866
#
1865
1867
# It is responsible for either launching a cluster of Puma workers or a single
1866
- # puma server.
1868
+ # Puma server.
1867
1869
class Launcher
1868
1870
def initialize (conf ,launcher_args = {})
1869
1871
@runner = nil
@@ -1984,7 +1986,7 @@ module Puma
1984
1986
# This part is important.
1985
1987
# Remember the block of ThreadPool.new will be called when a request added to the ThreadPool instance.
1986
1988
# And the block will process the request by calling method `process_client`.
1987
- # Let's step into this line later to see howpuma call the block.
1989
+ # Let's step into this line later to see howPuma call the block.
1988
1990
@thread_pool = ThreadPool .new (@min_threads ,
1989
1991
@max_threads ,
1990
1992
IOBuffer )do |client ,buffer |
@@ -2000,7 +2002,7 @@ module Puma
2000
2002
2001
2003
# ...
2002
2004
if process_now
2003
- # Process the request. You cantreat `client` as request.
2005
+ # Process the request. You canlook upon `client` as request.
2004
2006
# If you want to know more about 'process_client', please read part 3
2005
2007
# or search 'process_client' in this document.
2006
2008
process_client(client, buffer)
@@ -2014,7 +2016,7 @@ module Puma
2014
2016
2015
2017
if background# background: true (for this example)
2016
2018
# This part is important.
2017
- # Rememberpuma created a thread here!
2019
+ # RememberPuma created a thread here!
2018
2020
# We will know that the newly created thread's job is waiting for requests.
2019
2021
# When a request comes, the thread will transfer the request processing work to a thread in ThreadPool.
2020
2022
# The method `handle_servers` in thread's block will be executed immediately
@@ -2047,7 +2049,7 @@ module Puma
2047
2049
break if handle_check
2048
2050
else
2049
2051
if io= sock.accept_nonblock
2050
- # You can simplythink a Puma::Client instance as a request.
2052
+ # You can simplylook upon a Puma::Client instance as a request.
2051
2053
client= Client .new (io,@binder .env(sock))
2052
2054
2053
2055
# ...
@@ -2083,7 +2085,7 @@ module Puma
2083
2085
def initialize (min ,max ,* extra ,& block )
2084
2086
# ..
2085
2087
@mutex = Mutex .new
2086
- @todo = []# @todo is requests (inpuma , they are Puma::Client instances) which need to be processed.
2088
+ @todo = []# @todo is requests (inPuma , they are Puma::Client instances) which need to be processed.
2087
2089
@spawned = 0 # the count of @spawned threads
2088
2090
@min = Integer (min)# @min threads count
2089
2091
@max = Integer (max)# @max threads count
@@ -2149,7 +2151,7 @@ module Puma
2149
2151
@waiting -= 1
2150
2152
end
2151
2153
2152
- # `work` is the request (inpuma , it's Puma::Client instance) which need to be processed.
2154
+ # `work` is the request (inPuma , it's Puma::Client instance) which need to be processed.
2153
2155
work= todo.shiftif continue
2154
2156
end
2155
2157
@@ -2207,7 +2209,7 @@ module Puma
2207
2209
end
2208
2210
2209
2211
# work: #<Puma::Client:0x00007ff114ece6b0>
2210
- # You cantreat Puma::Client instance as a request.
2212
+ # You canlook upon Puma::Client instance as a request.
2211
2213
@todo << work
2212
2214
2213
2215
if @waiting < @todo .sizeand @spawned < @max
@@ -2241,9 +2243,9 @@ In `.run`, Puma will new a always running Thread for `ios = IO.select(#<TCPServe
2241
2243
2242
2244
Request is created from` ios ` object.
2243
2245
2244
- A thread inpuma threadPool will process the request.
2246
+ A thread inPuma threadPool will process the request.
2245
2247
2246
- The thread will invokerack apps'` call ` to get the response for the request.
2248
+ The thread will invokeRack apps'` call ` to get the response for the request.
2247
2249
2248
2250
###Exiting Puma
2249
2251
####Process and Thread
@@ -2311,7 +2313,7 @@ puts "Exit main thread"
2311
2313
` ` `
2312
2314
2313
2315
# ### Send `SIGTERM` to Puma
2314
- When you stoppuma by running` $ kill -s SIGTERM puma_process_id` , you will enter` setup_signals` in ` Puma::Launcher#run` .
2316
+ When you stopPuma by running` $ kill -s SIGTERM puma_process_id` , you will enter` setup_signals` in ` Puma::Launcher#run` .
2315
2317
` ` ` ruby
2316
2318
# .gems/puma-3.12.0/lib/puma/launcher.rb
2317
2319
module Puma
@@ -2453,14 +2455,14 @@ module Puma
2453
2455
2454
2456
# The created @thread is the @thread in` stop` method below.
2455
2457
@thread = Thread.new {
2456
- # FYI, this is in thepuma starting process.
2458
+ # FYI, this is in thePuma starting process.
2457
2459
# 'Thread.current.object_id' returns '70144220123860',
2458
2460
# which is the same as the 'Thread.current.object_id' in 'handle_servers' in Puma::Server#run
2459
2461
# def handle_servers
2460
2462
# begin
2461
2463
# # ...
2462
2464
# ensure
2463
- # # FYI, the 'ensure' part is in thepuma stopping process.
2465
+ # # FYI, the 'ensure' part is in thePuma stopping process.
2464
2466
# puts "#{ Thread .current.object_id} " # returns '70144220123860' too.
2465
2467
# end
2466
2468
# end
@@ -2533,11 +2535,11 @@ module Puma
2533
2535
2534
2536
# ...
2535
2537
ensure
2536
- # FYI, the 'ensure' part is in thepuma stopping process.
2538
+ # FYI, the 'ensure' part is in thePuma stopping process.
2537
2539
# 'Thread.current.object_id' returns '70144220123860',
2538
2540
# which is the same as the 'Thread.current.object_id' in 'Thread.new block' in Puma::Server#run
2539
2541
# @thread = Thread.new do
2540
- # # FYI, this is in thepuma starting process.
2542
+ # # FYI, this is in thePuma starting process.
2541
2543
# puts "#{Thread.current.object_id}" # returns '70144220123860'
2542
2544
# handle_servers
2543
2545
# end
@@ -2611,7 +2613,7 @@ module Puma
2611
2613
# ..
2612
2614
@mutex = Mutex .new
2613
2615
@spawned = 0 # The count of @spawned threads.
2614
- @todo = []# @todo is requests (inpuma , it's Puma::Client instance) which need to be processed.
2616
+ @todo = []# @todo is requests (inPuma , it's Puma::Client instance) which need to be processed.
2615
2617
@min = Integer (min)# @min threads count
2616
2618
@block = block# block will be called in method `spawn_thread` to process a request.
2617
2619
@workers = []