Skip to content

Commit 9581cc9

Browse files
committed
Fix reloading in dev with user-level fibers
1 parent a9e06a0 commit 9581cc9

5 files changed

Lines changed: 89 additions & 7 deletions

File tree

lib/rage/middleware/reloader.rb

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ def initialize(app)
55
Iodine.on_state(:on_start) do
66
Rage.code_loader.check_updated!
77
end
8+
89
@app = app
10+
@mutex = Mutex.new
911
end
1012

1113
def call(env)
@@ -21,13 +23,10 @@ def call(env)
2123
private
2224

2325
def with_reload
24-
if Rage.code_loader.check_updated!
25-
Fiber.new(blocking: true) {
26-
Rage.code_loader.reload
27-
yield
28-
}.resume
29-
else
30-
yield
26+
@mutex.synchronize do
27+
Rage.code_loader.reload if Rage.code_loader.check_updated!
3128
end
29+
30+
yield
3231
end
3332
end

spec/integration/integration_spec.rb

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,4 +274,79 @@
274274
expect(response.code).to eq(200)
275275
end
276276
end
277+
278+
context "with reload" do
279+
let(:controller) { Pathname.new("#{__dir__}/test_app/app/controllers/reload_controller.rb") }
280+
281+
before do
282+
@initial = controller.read
283+
end
284+
285+
after do
286+
controller.write(@initial)
287+
end
288+
289+
context "with new status" do
290+
before do
291+
controller.write <<~RUBY
292+
class ReloadController < RageController::API
293+
def verify
294+
head 207
295+
end
296+
end
297+
RUBY
298+
end
299+
300+
it "reloads the app" do
301+
response = HTTP.get("http://localhost:3000/reload/verify")
302+
expect(response.code).to eq(207)
303+
end
304+
end
305+
306+
context "with async code" do
307+
before do
308+
controller.write <<~RUBY
309+
class ReloadController < RageController::API
310+
def verify
311+
f1 = Fiber.schedule { sleep 0.1 }
312+
f2 = Fiber.schedule { sleep 0.2 }
313+
Fiber.await([f1, f2])
314+
315+
head 205
316+
end
317+
end
318+
RUBY
319+
end
320+
321+
it "reloads the app" do
322+
response = HTTP.get("http://localhost:3000/reload/verify")
323+
expect(response.code).to eq(205)
324+
end
325+
end
326+
327+
context "with parallel requests" do
328+
before do
329+
controller.write <<~RUBY
330+
class ReloadController < RageController::API
331+
def verify
332+
sleep 0.1
333+
head 208
334+
end
335+
end
336+
RUBY
337+
end
338+
339+
it "reloads the app" do
340+
requests = [
341+
Thread.new { HTTP.get("http://localhost:3000/reload/verify") },
342+
Thread.new { HTTP.get("http://localhost:3000/reload/verify") }
343+
]
344+
345+
requests.each(&:join)
346+
responses = requests.map(&:value)
347+
348+
expect(responses.map(&:code).uniq).to eq([208])
349+
end
350+
end
351+
end
277352
end
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class ReloadController < RageController::API
2+
def verify
3+
end
4+
end

spec/integration/test_app/config/environments/development.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@
88
# Specify the logger
99
config.logger = Rage::Logger.new("log/development.log")
1010
config.log_level = Logger::INFO
11+
12+
config.middleware.use Rage::Reloader
1113
end

spec/integration/test_app/config/routes.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
get "logs/custom", to: "logs#custom"
2727
get "logs/fiber", to: "logs#fiber"
2828

29+
get "reload/verify", to: "reload#verify"
30+
2931
mount ->(_) { [200, {}, ""] }, at: "/admin"
3032

3133
namespace :api do

0 commit comments

Comments
 (0)