svelte-on-rails 22.4.4 → 22.5.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/lib/svelte_on_rails/lib/boot_context.rb +43 -76
- data/lib/svelte_on_rails/lib/view_helper_support.rb +1 -1
- data/lib/svelte_on_rails/railtie.rb +3 -2
- data/lib/svelte_on_rails/ssr_client.rb +183 -92
- data/lib/tasks/general_tasks.rake +10 -0
- data/lib/tasks/ssr_client_tasks.rake +103 -0
- metadata +3 -2
- data/lib/tasks/svelte_on_rails_tasks.rake +0 -108
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d9c8ad89cdeda90311d9f2f60e3620d4bd87a8e148f40b6b9226136af7400ce3
|
|
4
|
+
data.tar.gz: cbc53e92bb4e44e97f0cd2076957618ddd8867d974490062d6ba9217930f134c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ff1bf4f5970164c5d185a3de9ea78506b16b8036dc04a8008ae020b20e6837cea4738f6d42af79aea11b563d048a4ed0c20e6d41abaddd61ff927cc6b72177ed
|
|
7
|
+
data.tar.gz: 13af465c198de0b3e918d30f68f0874f408e4d7b96e89c9467bdf3d193a4136bcc03684af5d2091e7670723529a089faa94c106eb743df49d9eeadcd28d24647
|
|
@@ -2,97 +2,64 @@ module SvelteOnRails
|
|
|
2
2
|
module BootContext
|
|
3
3
|
module_function
|
|
4
4
|
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
5
|
+
# Returns true when we are certain the current process is a Puma web
|
|
6
|
+
# server (or a `rails server` process that will boot Puma). Everywhere
|
|
7
|
+
# else (rake, console, runner, tests, generators, unknown wrappers)
|
|
8
|
+
# returns false. False negatives are safe because the SsrClient has a
|
|
9
|
+
# lazy-start fallback that kicks in on the first render request.
|
|
9
10
|
def serving_http?
|
|
10
|
-
# Explicit overrides
|
|
11
|
-
return true if ENV["SVELTE_ON_RAILS_FORCE_SSR"]
|
|
11
|
+
# 1. Explicit user overrides always win.
|
|
12
|
+
return true if ENV["SVELTE_ON_RAILS_FORCE_SSR"] == "1"
|
|
12
13
|
return false if ENV["SVELTE_ON_RAILS_DISABLE_SSR"] == "1"
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
#
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
#
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
#
|
|
30
|
-
|
|
15
|
+
# 2. Positive signal: `rails server` has been dispatched. This
|
|
16
|
+
# constant is defined by Rails::Command::ServerCommand before the
|
|
17
|
+
# app boots, and is a very reliable indicator.
|
|
18
|
+
return true if defined?(::Rails::Server)
|
|
19
|
+
|
|
20
|
+
# 3. Positive signal: a Puma::Launcher instance is already alive.
|
|
21
|
+
# Puma instantiates its Launcher inside Puma::Runner#run, which
|
|
22
|
+
# runs BEFORE Rails' after_initialize (because Puma requires the
|
|
23
|
+
# Rack app, and requiring the app is what triggers Rails boot).
|
|
24
|
+
# So by the time this method is called from our after_initialize
|
|
25
|
+
# hook, the launcher exists in ObjectSpace iff we are inside Puma.
|
|
26
|
+
return true if puma_launcher_alive?
|
|
27
|
+
|
|
28
|
+
# 4. Positive signal: launched via `puma` / `pumactl` binary directly.
|
|
29
|
+
# Redundant with (3) in most cases, but harmless and useful for
|
|
30
|
+
# exotic launchers that bypass Puma::Runner.
|
|
31
|
+
return true if program_basename == "puma"
|
|
32
|
+
|
|
33
|
+
# Everything else: not an HTTP-serving context (as far as we can tell
|
|
34
|
+
# at boot time). If we're wrong, the lazy fallback will handle it.
|
|
31
35
|
false
|
|
32
36
|
end
|
|
33
37
|
|
|
38
|
+
# Short human-readable label for the log line when we skip SSR startup.
|
|
34
39
|
def description
|
|
35
|
-
return "
|
|
36
|
-
return "
|
|
37
|
-
return "
|
|
38
|
-
return "rails
|
|
39
|
-
return "rails
|
|
40
|
-
return "
|
|
41
|
-
|
|
42
|
-
"program=#{File.basename($PROGRAM_NAME)}"
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# --- detectors -----------------------------------------------------------
|
|
46
|
-
|
|
47
|
-
def rake_task?
|
|
48
|
-
defined?(Rake) && Rake.respond_to?(:application) && Rake.application.top_level_tasks.any?
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def rails_console?
|
|
52
|
-
defined?(Rails::Console) ||
|
|
53
|
-
program_basename == "irb" ||
|
|
54
|
-
(defined?(IRB) && $PROGRAM_NAME.to_s.include?("irb"))
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def rails_runner?
|
|
58
|
-
defined?(Rails::Command::RunnerCommand) &&
|
|
59
|
-
Rails::Command.const_defined?(:RunnerCommand) &&
|
|
60
|
-
current_rails_command?("runner")
|
|
40
|
+
return "rails server" if defined?(::Rails::Server)
|
|
41
|
+
return "puma" if puma_launcher_alive? || program_basename == "puma"
|
|
42
|
+
return "rake: #{Rake.application.top_level_tasks.join(', ')}" if rake_task?
|
|
43
|
+
return "rails console" if defined?(::Rails::Console)
|
|
44
|
+
return "rails runner" if defined?(::Rails::Command::RunnerCommand)
|
|
45
|
+
return "rails dbconsole" if defined?(::Rails::DBConsole)
|
|
46
|
+
"program=#{program_basename}"
|
|
61
47
|
end
|
|
62
48
|
|
|
63
|
-
def
|
|
64
|
-
defined?(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
defined?(Rails::Generators) && current_rails_command?("generate", "destroy", "new")
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def test_runner?
|
|
72
|
-
!test_runner_name.nil?
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def test_runner_name
|
|
76
|
-
return "rspec" if $PROGRAM_NAME.to_s.include?("rspec")
|
|
77
|
-
return "minitest" if defined?(Minitest) && Minitest.respond_to?(:run) && !defined?(Rails::Server)
|
|
78
|
-
return "cucumber" if $PROGRAM_NAME.to_s.include?("cucumber")
|
|
79
|
-
nil
|
|
49
|
+
def puma_launcher_alive?
|
|
50
|
+
return false unless defined?(::Puma::Launcher)
|
|
51
|
+
ObjectSpace.each_object(::Puma::Launcher).any?
|
|
52
|
+
rescue
|
|
53
|
+
false
|
|
80
54
|
end
|
|
81
55
|
|
|
82
|
-
def
|
|
83
|
-
|
|
56
|
+
def rake_task?
|
|
57
|
+
defined?(::Rake) && Rake.respond_to?(:application) &&
|
|
58
|
+
Rake.application.top_level_tasks.any?
|
|
84
59
|
end
|
|
85
60
|
|
|
86
61
|
def program_basename
|
|
87
62
|
File.basename($PROGRAM_NAME.to_s)
|
|
88
63
|
end
|
|
89
|
-
|
|
90
|
-
# `rails <command>` sets ARGV[0] to the command name before Rails::Command
|
|
91
|
-
# dispatches. This is stable across Rails 6/7/8.
|
|
92
|
-
def current_rails_command?(*names)
|
|
93
|
-
argv0 = (defined?(ARGV) && ARGV.first) || nil
|
|
94
|
-
return false unless argv0
|
|
95
|
-
names.include?(argv0.to_s)
|
|
96
|
-
end
|
|
97
64
|
end
|
|
98
65
|
end
|
|
@@ -240,7 +240,7 @@ module SvelteOnRails
|
|
|
240
240
|
def render_with_ssr_server(caller_loc)
|
|
241
241
|
return {} unless @conf.configs[:ssr_server]
|
|
242
242
|
|
|
243
|
-
result = SvelteOnRails::SsrClient.instance.render(
|
|
243
|
+
result = SvelteOnRails::SsrClient.instance(caller: "Request/View-helper").render(
|
|
244
244
|
component_paths,
|
|
245
245
|
cached_props,
|
|
246
246
|
debug?,
|
|
@@ -23,7 +23,7 @@ module SvelteOnRails
|
|
|
23
23
|
)
|
|
24
24
|
$stdout.flush
|
|
25
25
|
elsif SvelteOnRails::Configuration.instance.configs[:ssr]
|
|
26
|
-
SvelteOnRails::SsrClient.instance
|
|
26
|
+
SvelteOnRails::SsrClient.instance(caller: 'initializer/booting')
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
end
|
|
@@ -52,8 +52,9 @@ module SvelteOnRails
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
rake_tasks do
|
|
55
|
-
load File.expand_path("../../tasks/
|
|
55
|
+
load File.expand_path("../../tasks/general_tasks.rake", __FILE__)
|
|
56
56
|
load File.expand_path("../../tasks/cache_tasks.rake", __FILE__)
|
|
57
|
+
load File.expand_path("../../tasks/ssr_client_tasks.rake", __FILE__)
|
|
57
58
|
end
|
|
58
59
|
end
|
|
59
60
|
end
|
|
@@ -10,34 +10,50 @@ module SvelteOnRails
|
|
|
10
10
|
:logfile_max_lines,
|
|
11
11
|
:socket_path,
|
|
12
12
|
:ssr_server_bin_path,
|
|
13
|
-
:node_bin
|
|
13
|
+
:node_bin,
|
|
14
|
+
:initialized_by
|
|
14
15
|
|
|
15
16
|
# methods
|
|
16
17
|
|
|
17
|
-
def self.instance
|
|
18
|
-
|
|
18
|
+
def self.instance(caller: nil)
|
|
19
|
+
|
|
20
|
+
@instance ||= new(caller: caller)
|
|
21
|
+
@instance
|
|
19
22
|
end
|
|
20
23
|
|
|
21
|
-
def initialize
|
|
24
|
+
def initialize(caller: nil)
|
|
25
|
+
|
|
26
|
+
@initialized_by = caller
|
|
27
|
+
|
|
28
|
+
File.open(SvelteOnRails::Lib::Utils.ssr_server_logfile, 'w') do |f|
|
|
29
|
+
f.sync = true
|
|
30
|
+
f.puts("[#{Time.now.utc.iso8601(3)} ppid:#{Process.ppid} pid:#{Process.pid}] >>> Logfile deleted on initializing SsrClient, called by #{caller} <<<")
|
|
31
|
+
end
|
|
22
32
|
|
|
23
|
-
SvelteOnRails::Lib::Utils.ssr_server_logfile.delete if SvelteOnRails::Lib::Utils.ssr_server_logfile.exist?
|
|
24
33
|
|
|
25
|
-
@
|
|
34
|
+
@socket_namespace = [
|
|
35
|
+
"svelte",
|
|
36
|
+
Rails.application.class.module_parent_name[0..30],
|
|
37
|
+
short_env
|
|
38
|
+
].join("-")
|
|
39
|
+
@socket_path = socket_path_fresh
|
|
26
40
|
|
|
27
41
|
@logfile_path = Rails.root.join("log/svelte-ssr-server-#{Rails.env}.log")
|
|
28
42
|
@logfile_max_lines = build_logfile_max_lines
|
|
29
|
-
@socket_path = @helpers.socket_path
|
|
30
43
|
@ssr_server = SvelteOnRails::Configuration.instance.configs[:ssr_server]
|
|
31
|
-
@ssr_server_bin_path =
|
|
44
|
+
@ssr_server_bin_path = SvelteOnRails::Configuration.instance.ssr_server_bin_path
|
|
45
|
+
@started = Time.now
|
|
32
46
|
|
|
33
47
|
File.delete(restart_marker_file) if File.exist?(restart_marker_file)
|
|
34
48
|
|
|
49
|
+
SvelteOnRails::SsrClientControlChannel.install_control_listener
|
|
50
|
+
|
|
35
51
|
if @ssr_server
|
|
36
52
|
|
|
37
53
|
start_node_server!
|
|
38
54
|
|
|
39
55
|
at_exit do
|
|
40
|
-
|
|
56
|
+
shutdown(caller: 'at_exit')
|
|
41
57
|
File.delete(restart_marker_file) if File.exist?(restart_marker_file)
|
|
42
58
|
end
|
|
43
59
|
else
|
|
@@ -169,21 +185,12 @@ module SvelteOnRails
|
|
|
169
185
|
|
|
170
186
|
SvelteOnRails::Lib::Utils.ssr_server_log("SOR start_node_server! called", ssr_logfile_only: !restart_after_failure)
|
|
171
187
|
|
|
172
|
-
# notice ppid
|
|
173
|
-
FileUtils.mkdir_p(@helpers.ssr_client_ppid_file.dirname)
|
|
174
|
-
File.write(@helpers.ssr_client_ppid_file, Process.ppid.to_s)
|
|
175
|
-
if @helpers.ssr_client_ppid_file.exist?
|
|
176
|
-
SvelteOnRails::Lib::Utils.ssr_server_log("File #{@helpers.ssr_client_ppid_file} written, PPID: #{Process.ppid}", ssr_logfile_only: true)
|
|
177
|
-
else
|
|
178
|
-
SvelteOnRails::Lib::Utils.ssr_server_log("ERROR: File #{@helpers.ssr_client_ppid_file} could not be written")
|
|
179
|
-
end
|
|
180
|
-
|
|
181
188
|
start = Time.now
|
|
182
189
|
|
|
183
190
|
@node_server_output = {}
|
|
184
191
|
Thread.new do
|
|
185
192
|
stdout, stderr, status = Open3.capture3(
|
|
186
|
-
|
|
193
|
+
start_node_server_command(started_by),
|
|
187
194
|
chdir: Rails.root
|
|
188
195
|
)
|
|
189
196
|
@node_server_output = {
|
|
@@ -215,7 +222,7 @@ module SvelteOnRails
|
|
|
215
222
|
end
|
|
216
223
|
SvelteOnRails::Lib::Utils.ssr_server_log("Server responded successfully")
|
|
217
224
|
|
|
218
|
-
|
|
225
|
+
cleanup_leftover_processes
|
|
219
226
|
end
|
|
220
227
|
|
|
221
228
|
def restart_my_server(tag = nil)
|
|
@@ -234,7 +241,7 @@ module SvelteOnRails
|
|
|
234
241
|
Rails.logger.error(msg)
|
|
235
242
|
SvelteOnRails::Lib::Utils.ssr_server_log("[ERROR] #{msg}")
|
|
236
243
|
|
|
237
|
-
|
|
244
|
+
shutdown(caller: 'restart')
|
|
238
245
|
begin
|
|
239
246
|
start_node_server!("#{tag.gsub(' ', '-') + '-' if tag}#{count}", restart_after_failure: true)
|
|
240
247
|
rescue
|
|
@@ -253,6 +260,57 @@ module SvelteOnRails
|
|
|
253
260
|
nil
|
|
254
261
|
end
|
|
255
262
|
|
|
263
|
+
def uptime
|
|
264
|
+
Time.now - @started
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def start_node_server_command(started_by = '')
|
|
268
|
+
workers = SvelteOnRails::Configuration.instance.configs[:ssr_server_workers]
|
|
269
|
+
[
|
|
270
|
+
(started_by ? "SVELTE_SSR_SERVER_STARTED_BY=#{started_by}" : nil),
|
|
271
|
+
SvelteOnRails::Configuration.instance.node_bin_path,
|
|
272
|
+
@ssr_server_bin_path,
|
|
273
|
+
socket_path,
|
|
274
|
+
(workers > 1 ? "--workers=#{workers}" : nil)
|
|
275
|
+
].compact.join(' ')
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def shutdown(caller: '')
|
|
279
|
+
SsrClient.instance_variable_set(:@instance, nil)
|
|
280
|
+
SvelteOnRails::Lib::Utils.ssr_server_log("Shutting down SSR client, ppid: #{Process.ppid} (#{caller})")
|
|
281
|
+
terminate_node_processes(own_processes, label: "own")
|
|
282
|
+
{
|
|
283
|
+
success: true
|
|
284
|
+
}
|
|
285
|
+
rescue => e
|
|
286
|
+
{
|
|
287
|
+
error: e
|
|
288
|
+
}
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# NODE PROCESS MANAGEMENT
|
|
292
|
+
|
|
293
|
+
SsrProcess = Struct.new(:pid, :ppid, :socket_path, keyword_init: true)
|
|
294
|
+
|
|
295
|
+
def own_processes
|
|
296
|
+
scan_processes.select { |p| p.ppid == Process.ppid }
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def leftover_processes
|
|
300
|
+
scan_processes.reject { |p| p.ppid == Process.ppid }
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def leftover_sockets
|
|
304
|
+
scan_sockets.reject { |s| s[:ppid] == Process.ppid }
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def cleanup_leftover_processes
|
|
308
|
+
terminate_node_processes(leftover_processes, label: "leftover")
|
|
309
|
+
delete_sockets(leftover_sockets.map { |s| s[:path] }, label: "leftover")
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# END node process management
|
|
313
|
+
|
|
256
314
|
private
|
|
257
315
|
|
|
258
316
|
def restart_marker_file
|
|
@@ -325,34 +383,8 @@ module SvelteOnRails
|
|
|
325
383
|
end
|
|
326
384
|
end
|
|
327
385
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
class SsrServerHelpers
|
|
331
|
-
|
|
332
|
-
# theese helpers are used from the :check rake task
|
|
333
|
-
# For that reason they are within a separate class
|
|
334
|
-
|
|
335
|
-
attr_reader :socket_namespace,
|
|
336
|
-
:socket_path,
|
|
337
|
-
:ssr_server_bin_path
|
|
338
|
-
|
|
339
|
-
def initialize
|
|
340
|
-
|
|
341
|
-
@socket_namespace = [
|
|
342
|
-
"svelte-ssr",
|
|
343
|
-
Rails.application.class.module_parent_name[0..30],
|
|
344
|
-
Rails.env,
|
|
345
|
-
].join("-")
|
|
346
|
-
|
|
347
|
-
@ssr_server_bin_path = SvelteOnRails::Configuration.instance.ssr_server_bin_path
|
|
348
|
-
|
|
349
|
-
end
|
|
350
|
-
|
|
351
|
-
def ssr_client_ppid_file
|
|
352
|
-
Rails.root.join("tmp", "pids", 'svelte_on_rails.ppid')
|
|
353
|
-
end
|
|
354
|
-
|
|
355
|
-
def socket_path(ppid: Process.ppid)
|
|
386
|
+
def socket_path_fresh
|
|
387
|
+
ppid = Process.ppid
|
|
356
388
|
app_sock = Rails.root.join("tmp/sockets/#{@socket_namespace}-#{ppid}.sock")
|
|
357
389
|
FileUtils.mkdir_p(File.dirname(app_sock))
|
|
358
390
|
|
|
@@ -368,47 +400,9 @@ module SvelteOnRails
|
|
|
368
400
|
fallback
|
|
369
401
|
end
|
|
370
402
|
|
|
371
|
-
|
|
372
|
-
workers = SvelteOnRails::Configuration.instance.configs[:ssr_server_workers]
|
|
373
|
-
[
|
|
374
|
-
(started_by ? "SVELTE_SSR_SERVER_STARTED_BY=#{started_by}" : nil),
|
|
375
|
-
SvelteOnRails::Configuration.instance.node_bin_path,
|
|
376
|
-
@ssr_server_bin_path,
|
|
377
|
-
socket_path(ppid: ppid),
|
|
378
|
-
(workers > 1 ? "--workers=#{workers}" : nil)
|
|
379
|
-
].compact.join(' ')
|
|
380
|
-
end
|
|
381
|
-
|
|
382
|
-
SsrProcess = Struct.new(:pid, :ppid, :socket_path, keyword_init: true)
|
|
383
|
-
|
|
384
|
-
def own_processes(current_ppid: Process.ppid)
|
|
385
|
-
scan_processes.select { |p| p.ppid == current_ppid }
|
|
386
|
-
end
|
|
387
|
-
|
|
388
|
-
def leftover_processes(current_ppid: Process.ppid)
|
|
389
|
-
scan_processes.reject { |p| p.ppid == current_ppid }
|
|
390
|
-
end
|
|
391
|
-
|
|
392
|
-
def leftover_sockets(current_ppid: Process.ppid)
|
|
393
|
-
scan_sockets.reject { |s| s[:ppid] == current_ppid }
|
|
394
|
-
end
|
|
395
|
-
|
|
396
|
-
def cleanup_leftover_processes(current_ppid: Process.ppid)
|
|
397
|
-
terminate_processes(leftover_processes(current_ppid: current_ppid), label: "leftover")
|
|
398
|
-
delete_sockets(leftover_sockets(current_ppid: current_ppid).map { |s| s[:path] }, label: "leftover")
|
|
399
|
-
end
|
|
400
|
-
|
|
401
|
-
def shutdown(current_ppid: Process.ppid)
|
|
402
|
-
terminate_processes(own_processes(current_ppid: current_ppid), label: "own")
|
|
403
|
-
ensure
|
|
404
|
-
File.delete(ssr_client_ppid_file) if File.exist?(ssr_client_ppid_file)
|
|
405
|
-
end
|
|
406
|
-
|
|
407
|
-
private
|
|
403
|
+
# NODE PROCESS MANAGEMENT
|
|
408
404
|
|
|
409
|
-
|
|
410
|
-
# SIGINT the primary first (lowest pid per socket group); survivors get SIGINT too.
|
|
411
|
-
def terminate_processes(processes, label:)
|
|
405
|
+
def terminate_node_processes(processes, label:)
|
|
412
406
|
return if processes.empty?
|
|
413
407
|
|
|
414
408
|
processes.group_by(&:socket_path).values.flat_map { |g| g.sort_by(&:pid) }.each do |p|
|
|
@@ -431,7 +425,6 @@ module SvelteOnRails
|
|
|
431
425
|
SvelteOnRails::Lib::Utils.ssr_server_log("Deleted #{socket_paths.size} #{label} socket#{'s' if socket_paths.size != 1}")
|
|
432
426
|
end
|
|
433
427
|
|
|
434
|
-
# All running SSR processes matching our namespace (any ppid).
|
|
435
428
|
def scan_processes
|
|
436
429
|
stdout, = Open3.capture3("ps aux | grep svelte | grep -v grep")
|
|
437
430
|
regex = %r{(/\S*#{Regexp.escape(@socket_namespace)}-(\d+)\.sock)\b}
|
|
@@ -443,8 +436,6 @@ module SvelteOnRails
|
|
|
443
436
|
end
|
|
444
437
|
end
|
|
445
438
|
|
|
446
|
-
# All socket files on disk matching our namespace (any ppid).
|
|
447
|
-
# Looks in both the app's tmp/sockets dir and the macOS/BSD fallback dir.
|
|
448
439
|
def scan_sockets
|
|
449
440
|
dirs = [Rails.root.join("tmp/sockets").to_s, "/tmp/svelte"]
|
|
450
441
|
regex = /#{Regexp.escape(@socket_namespace)}-(\d+)\.sock\z/
|
|
@@ -453,6 +444,106 @@ module SvelteOnRails
|
|
|
453
444
|
.filter_map { |path| (m = path.match(regex)) && { path: path, ppid: m[1].to_i } }
|
|
454
445
|
end
|
|
455
446
|
|
|
447
|
+
# END node process management
|
|
448
|
+
|
|
449
|
+
def short_env
|
|
450
|
+
|
|
451
|
+
name = Rails.env.to_s
|
|
452
|
+
|
|
453
|
+
short = {
|
|
454
|
+
"development" => "dev",
|
|
455
|
+
"production" => "prod",
|
|
456
|
+
"staging" => "stage",
|
|
457
|
+
}[name]
|
|
458
|
+
|
|
459
|
+
return name unless short
|
|
460
|
+
return name if Rails.root.join("config", "environments", "#{short}.rb").exist?
|
|
461
|
+
short
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
class SsrClientControlChannel
|
|
467
|
+
|
|
468
|
+
SOCKET_FILENAME = "svelte-ctl.sock"
|
|
469
|
+
|
|
470
|
+
# Full path of the control socket.
|
|
471
|
+
# Sits next to the SSR socket in tmp/sockets, or in the /tmp/svelte
|
|
472
|
+
# fallback directory when Rails.root pushes total length over 104 chars.
|
|
473
|
+
def self.socket_path
|
|
474
|
+
primary = Rails.root.join("tmp", "sockets", SOCKET_FILENAME)
|
|
475
|
+
return primary if primary.to_s.length < 104
|
|
476
|
+
|
|
477
|
+
fallback_dir = Pathname.new('/tmp/svelte')
|
|
478
|
+
FileUtils.mkdir_p(fallback_dir)
|
|
479
|
+
FileUtils.chmod(0777, fallback_dir)
|
|
480
|
+
fallback_dir.join(SOCKET_FILENAME)
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
# enable communication by rake task for admin purposes
|
|
484
|
+
def self.install_control_listener
|
|
485
|
+
|
|
486
|
+
path = socket_path.to_s
|
|
487
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
488
|
+
File.unlink(path) if File.exist?(path)
|
|
489
|
+
|
|
490
|
+
server = UNIXServer.new(path)
|
|
491
|
+
File.chmod(0600, path)
|
|
492
|
+
|
|
493
|
+
Thread.new do
|
|
494
|
+
loop do
|
|
495
|
+
client = server.accept
|
|
496
|
+
begin
|
|
497
|
+
request = client.gets&.strip.to_sym
|
|
498
|
+
client_instance = SsrClient.instance(caller: 'rake task (manual)')
|
|
499
|
+
|
|
500
|
+
response = case request
|
|
501
|
+
when :status
|
|
502
|
+
{
|
|
503
|
+
env: Rails.env,
|
|
504
|
+
uptime: client_instance.uptime,
|
|
505
|
+
request: request,
|
|
506
|
+
socket_path: client_instance.socket_path,
|
|
507
|
+
initialized_by: client_instance.initialized_by,
|
|
508
|
+
ping: client_instance.ping?,
|
|
509
|
+
start_node_server_command: client_instance.start_node_server_command
|
|
510
|
+
}
|
|
511
|
+
when :stop
|
|
512
|
+
begin
|
|
513
|
+
client_instance.shutdown
|
|
514
|
+
{
|
|
515
|
+
success: true
|
|
516
|
+
}
|
|
517
|
+
rescue => e
|
|
518
|
+
{
|
|
519
|
+
error: "Failed to stop SSR server => #{e}"
|
|
520
|
+
}
|
|
521
|
+
end
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
client.puts(response.to_json)
|
|
525
|
+
rescue => e
|
|
526
|
+
SvelteOnRails::Lib::Utils.ssr_server_log(
|
|
527
|
+
"[control] handler error: #{e.class}: #{e.message}",
|
|
528
|
+
ssr_logfile_only: true
|
|
529
|
+
)
|
|
530
|
+
ensure
|
|
531
|
+
client.close rescue nil
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
at_exit do
|
|
537
|
+
server.close rescue nil
|
|
538
|
+
File.unlink(path) rescue nil
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
SvelteOnRails::Lib::Utils.ssr_server_log(
|
|
542
|
+
"Control listener installed on #{path}",
|
|
543
|
+
ssr_logfile_only: true
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
end
|
|
456
547
|
end
|
|
457
548
|
|
|
458
549
|
class SsrError < StandardError; end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
namespace :svelte_on_rails do
|
|
2
|
+
|
|
3
|
+
desc "Check svelte-on-rails setup and SSR server status"
|
|
4
|
+
task :check do
|
|
5
|
+
|
|
6
|
+
@line_width = 130
|
|
7
|
+
|
|
8
|
+
# SSR CLIENT STATUS
|
|
9
|
+
|
|
10
|
+
cs = get_from_ssr_client(:status)
|
|
11
|
+
exit(1) unless cs
|
|
12
|
+
client_status = JSON.parse(cs).symbolize_keys
|
|
13
|
+
configs = SvelteOnRails::Configuration.instance
|
|
14
|
+
socket_path = client_status[:socket_path]
|
|
15
|
+
|
|
16
|
+
puts
|
|
17
|
+
puts '=' * @line_width
|
|
18
|
+
puts
|
|
19
|
+
puts "INFO FROM THE SSR CLIENT (Rails-side):"
|
|
20
|
+
puts
|
|
21
|
+
puts " Rails env : #{client_status[:env]}"
|
|
22
|
+
puts " Uptime : #{client_status[:uptime].round(0)}sec"
|
|
23
|
+
puts " Initialized by : #{client_status[:initialized_by]}"
|
|
24
|
+
puts " Socket (Node) : #{socket_path} (#{File.socket?(socket_path) ? 'Present/OK' : 'NOT FOUND!'})"
|
|
25
|
+
puts " Ping to Node : #{client_status[:ping] ? 'SUCCESS' : 'FAILED'}"
|
|
26
|
+
puts ' Node bin : ' + configs.node_bin_path.to_s
|
|
27
|
+
puts ' Node version : ' + configs.node_version_test
|
|
28
|
+
puts ' SSR Server bin : ' + configs.ssr_server_bin_path.to_s
|
|
29
|
+
puts ' NPM package version : ' + configs.npm_package_version_test.to_s
|
|
30
|
+
puts
|
|
31
|
+
|
|
32
|
+
# NODE SERVER STATUS
|
|
33
|
+
|
|
34
|
+
curl_installed = system('which curl > /dev/null 2>&1')
|
|
35
|
+
if !curl_installed
|
|
36
|
+
puts '*' * @line_width
|
|
37
|
+
puts ' ERROR'
|
|
38
|
+
puts ' curl is not installed on this machine.'
|
|
39
|
+
puts ' unable to check node server status.'
|
|
40
|
+
puts '*' * @line_width
|
|
41
|
+
exit(1)
|
|
42
|
+
else
|
|
43
|
+
puts '=' * @line_width
|
|
44
|
+
puts
|
|
45
|
+
puts "SSR SERVER (NODE) STATUS:"
|
|
46
|
+
puts
|
|
47
|
+
curl_cmd = "curl --unix-socket #{socket_path} http://localhost"
|
|
48
|
+
stdout, stderr, status = Open3.capture3(curl_cmd)
|
|
49
|
+
puts stdout
|
|
50
|
+
puts
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
puts '=' * @line_width
|
|
54
|
+
puts
|
|
55
|
+
puts 'ADDITIONAL INFO:'
|
|
56
|
+
puts
|
|
57
|
+
puts 'How was the node bin path determined:'
|
|
58
|
+
configs.instance_variable_get(:@node_bin_path_log).each_with_index do |line, index|
|
|
59
|
+
puts " #{index + 1} #{line}"
|
|
60
|
+
end
|
|
61
|
+
puts
|
|
62
|
+
puts 'Commands:'
|
|
63
|
+
puts " • start node server (node path/to/svelte-ssr-server.js path/to/socket.sock):"
|
|
64
|
+
puts " • #{client_status[:start_node_server_command]}"
|
|
65
|
+
puts
|
|
66
|
+
puts '=' * @line_width
|
|
67
|
+
puts
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
namespace :ssr_client do
|
|
72
|
+
|
|
73
|
+
desc 'For development: to simulate when a client did not start on deploy (Then, on the first request of a svelte component - if not cached! - it must start)'
|
|
74
|
+
task :stop do
|
|
75
|
+
r = get_from_ssr_client(:stop)
|
|
76
|
+
if r['success']
|
|
77
|
+
puts "SSR client stopped successfully."
|
|
78
|
+
else
|
|
79
|
+
puts "ERROR: #{r}"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def get_from_ssr_client(request)
|
|
86
|
+
|
|
87
|
+
raise "invalid request" unless [:status, :stop].include?(request)
|
|
88
|
+
|
|
89
|
+
path = SvelteOnRails::SsrClientControlChannel.socket_path.to_path
|
|
90
|
+
unless File.socket?(path)
|
|
91
|
+
puts "*" * @line_width
|
|
92
|
+
puts "ERROR: Control socket not found at #{path} — is Rails running?"
|
|
93
|
+
puts "*" * @line_width
|
|
94
|
+
return
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
sock = UNIXSocket.new(path)
|
|
98
|
+
sock.puts(request)
|
|
99
|
+
response = sock.gets
|
|
100
|
+
sock.close
|
|
101
|
+
response
|
|
102
|
+
end
|
|
103
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: svelte-on-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 22.
|
|
4
|
+
version: 22.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Christian Sedlmair
|
|
@@ -102,7 +102,8 @@ files:
|
|
|
102
102
|
- lib/svelte_on_rails/turbo_stream.rb
|
|
103
103
|
- lib/svelte_on_rails/view_helpers.rb
|
|
104
104
|
- lib/tasks/cache_tasks.rake
|
|
105
|
-
- lib/tasks/
|
|
105
|
+
- lib/tasks/general_tasks.rake
|
|
106
|
+
- lib/tasks/ssr_client_tasks.rake
|
|
106
107
|
- templates/config_base/app/frontend/ssr/ssr.js
|
|
107
108
|
- templates/config_base/config/svelte_on_rails.yml
|
|
108
109
|
- templates/config_base/tsconfig.json
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
namespace :svelte_on_rails do
|
|
2
|
-
desc "Precompile Svelte components for server side rendering"
|
|
3
|
-
task :precompile do
|
|
4
|
-
SvelteOnRails::Configuration.instance.vite_build
|
|
5
|
-
end
|
|
6
|
-
|
|
7
|
-
desc "check ssr requirements and status"
|
|
8
|
-
task :check do
|
|
9
|
-
|
|
10
|
-
line_width = 100
|
|
11
|
-
configs = SvelteOnRails::Configuration.instance
|
|
12
|
-
ppid_file = Rails.root.join("tmp", "pids", 'svelte_on_rails.ppid')
|
|
13
|
-
ppid = (ppid_file.exist? ? File.read(ppid_file).chomp : nil)
|
|
14
|
-
server_helpers = SvelteOnRails::SsrServerHelpers.new
|
|
15
|
-
socket_path = server_helpers.socket_path(ppid: ppid)
|
|
16
|
-
|
|
17
|
-
unless File.socket?(socket_path)
|
|
18
|
-
puts "*" * 80
|
|
19
|
-
puts "ERROR: socket file does not exist or is not a socket: #{socket_path}"
|
|
20
|
-
puts "Do you have set RAILS_ENV correctly?"
|
|
21
|
-
puts "*" * 80
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
unless ppid_file.exist?
|
|
25
|
-
puts "*" * 80
|
|
26
|
-
puts "ERROR: PPID File does not exist: #{ppid_file}"
|
|
27
|
-
puts "Is the app running?"
|
|
28
|
-
puts "*" * 80
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
curl_installed = system('which curl > /dev/null 2>&1')
|
|
32
|
-
if curl_installed
|
|
33
|
-
curl_cmd = "curl --unix-socket #{socket_path} http://localhost"
|
|
34
|
-
stdout, stderr, status = Open3.capture3(curl_cmd + '/health')
|
|
35
|
-
srv_details = (JSON.parse(stdout) rescue {})
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
puts
|
|
39
|
-
puts '=' * line_width
|
|
40
|
-
puts "Svelte on Rails SSR Server Status:"
|
|
41
|
-
puts " Rails env: #{Rails.env}"
|
|
42
|
-
if srv_details['uptime']
|
|
43
|
-
puts " Uptime: #{srv_details['uptime'].round(0)}sec"
|
|
44
|
-
else
|
|
45
|
-
puts " Status: not running"
|
|
46
|
-
end
|
|
47
|
-
puts '=' * line_width
|
|
48
|
-
puts
|
|
49
|
-
puts 'Node'
|
|
50
|
-
puts label('Node bin') + configs.node_bin_path.to_s
|
|
51
|
-
puts label('Node version') + configs.node_version_test
|
|
52
|
-
puts label('SSR Server bin') + configs.ssr_server_bin_path.to_s
|
|
53
|
-
puts label('SSR Server version') + configs.npm_package_version_test.to_s
|
|
54
|
-
puts
|
|
55
|
-
puts 'Rails instance'
|
|
56
|
-
puts label('Process.ppid') + ppid.to_s
|
|
57
|
-
puts label('Socket') + socket_path.to_s
|
|
58
|
-
puts
|
|
59
|
-
puts '=' * line_width
|
|
60
|
-
puts
|
|
61
|
-
puts 'MORE DETAILS:'
|
|
62
|
-
puts
|
|
63
|
-
puts 'How was the node bin path determined:'
|
|
64
|
-
configs.instance_variable_get(:@node_bin_path_log).each do |line|
|
|
65
|
-
puts " • #{line}"
|
|
66
|
-
puts " • kill #{line}"
|
|
67
|
-
end
|
|
68
|
-
puts
|
|
69
|
-
puts 'Commands:'
|
|
70
|
-
puts " • node path/to/svelte-ssr-server.js path/to/socket.sock:"
|
|
71
|
-
puts " • #{server_helpers.start_node_server_command(nil)}"
|
|
72
|
-
if srv_details['pid']
|
|
73
|
-
puts " • #{curl_cmd}"
|
|
74
|
-
puts " • kill #{srv_details['pid']}" if srv_details['pid']
|
|
75
|
-
end
|
|
76
|
-
puts
|
|
77
|
-
|
|
78
|
-
puts '=' * line_width
|
|
79
|
-
puts
|
|
80
|
-
puts 'NODE INSTANCE INFO:'
|
|
81
|
-
puts ' (output of the above mentioned curl command)'
|
|
82
|
-
puts
|
|
83
|
-
puts '-' * line_width
|
|
84
|
-
if curl_installed
|
|
85
|
-
stdout, stderr, status = Open3.capture3(curl_cmd)
|
|
86
|
-
if status.success?
|
|
87
|
-
puts stdout
|
|
88
|
-
else
|
|
89
|
-
puts "curl exited with status #{status.exitstatus}"
|
|
90
|
-
puts stderr unless stderr.to_s.strip.empty?
|
|
91
|
-
end
|
|
92
|
-
else
|
|
93
|
-
puts "curl is not installed on this machine, skipping execution."
|
|
94
|
-
end
|
|
95
|
-
puts
|
|
96
|
-
puts '=' * line_width
|
|
97
|
-
puts
|
|
98
|
-
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def label(msg)
|
|
102
|
-
l = msg.length
|
|
103
|
-
" #{msg}:"[0..20] + (msg.length > 22 ? ':' : '') + ' ' * (20 - l)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
Rake::Task["assets:precompile"].enhance ["svelte_on_rails:precompile"]
|