execjs-pcruntime 0.2.1 → 0.2.2
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/execjs/pcruntime/context_process_runtime.rb +84 -14
- data/lib/execjs/pcruntime/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ed5dacd1dab7ff7ef42dc43084d6c00da36cd3f228e02517cd0e33492bce55b
|
4
|
+
data.tar.gz: 486214245b193a1000bd930758767776398c3f4f47f68a49086a09cf500300eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz: '
|
6
|
+
metadata.gz: b625a73b8da1b28469a4df46500cba801b16279a81adde6479d0671d7f2a942d4d45f73552bd967422237bcc2dcc398083310dea69c24b81c7dc00f031f43d6d
|
7
|
+
data.tar.gz: '088e05880ba92eaf812c25aac7c6e56935294c1af8cc36693fb1d7a3ae26da0f783c8307a7a3f283f976a43cff595bc1b0ec7101e921dc7c72ec8b991be421ac'
|
@@ -20,10 +20,7 @@ module ExecJS
|
|
20
20
|
super
|
21
21
|
|
22
22
|
# @type [JSRuntimeHandle]
|
23
|
-
@runtime = runtime.create_runtime_handle
|
24
|
-
|
25
|
-
# load initial source to Context
|
26
|
-
@runtime.evaluate(source.encode('UTF-8'))
|
23
|
+
@runtime = runtime.create_runtime_handle source.encode('UTF-8')
|
27
24
|
end
|
28
25
|
|
29
26
|
# implementation of ExecJS::Runtime::Context#eval
|
@@ -52,17 +49,19 @@ module ExecJS
|
|
52
49
|
|
53
50
|
# Handle of JavaScript Runtime
|
54
51
|
# launch Runtime by .new and finished on finalizer
|
52
|
+
# rubocop:disable Metrics/ClassLength
|
55
53
|
class JSRuntimeHandle
|
56
54
|
# @param [Array<String>] binary Launch command for the node(or similar JavaScript Runtime) binary,
|
57
55
|
# such as ['node'], ['deno', 'run'].
|
58
56
|
# @param [String] initial_source_path Path of .js Runtime loads at startup.
|
59
|
-
def initialize(binary, initial_source_path)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
57
|
+
def initialize(binary, initial_source_path, compile_source, semaphore)
|
58
|
+
@semaphore = semaphore
|
59
|
+
@binary = binary
|
60
|
+
@initial_source_path = initial_source_path
|
61
|
+
@compile_source = compile_source
|
62
|
+
@recreate_process_lock = Mutex.new
|
63
|
+
@runtime_pid, @socket_path = initialize_process
|
64
|
+
evaluate(@compile_source)
|
66
65
|
ObjectSpace.define_finalizer(self, self.class.finalizer(@runtime_pid))
|
67
66
|
end
|
68
67
|
|
@@ -70,7 +69,35 @@ module ExecJS
|
|
70
69
|
# @param [String] source JavaScript source code
|
71
70
|
# @return [object]
|
72
71
|
def evaluate(source)
|
73
|
-
|
72
|
+
socket_path = @socket_path
|
73
|
+
post_request(socket_path, '/eval', 'text/javascript', source)
|
74
|
+
rescue RuntimeError, ProgramError => e
|
75
|
+
raise e
|
76
|
+
rescue StandardError => e
|
77
|
+
warn e.full_message
|
78
|
+
retry if socket_path != @socket_path
|
79
|
+
@recreate_process_lock.synchronize do
|
80
|
+
@runtime_pid, @socket_path = recreate_process if socket_path == @socket_path
|
81
|
+
end
|
82
|
+
retry
|
83
|
+
end
|
84
|
+
|
85
|
+
# kill JavaScript runtime process and re-create
|
86
|
+
# @return [[Integer, String]] [runtime_pid, socket_path]
|
87
|
+
def recreate_process
|
88
|
+
runtime_pid = @runtime_pid
|
89
|
+
begin
|
90
|
+
err = self.class.kill_process(runtime_pid)
|
91
|
+
warn err.full_message unless err.nil?
|
92
|
+
runtime_pid, socket_path = initialize_process
|
93
|
+
post_request(socket_path, '/eval', 'text/javascript', @compile_source)
|
94
|
+
rescue RuntimeError, ProgramError => e
|
95
|
+
raise e
|
96
|
+
rescue StandardError => e
|
97
|
+
warn e.full_message
|
98
|
+
retry
|
99
|
+
end
|
100
|
+
[runtime_pid, socket_path]
|
74
101
|
end
|
75
102
|
|
76
103
|
# Create a procedure to kill the Process that has specified pid.
|
@@ -96,6 +123,20 @@ module ExecJS
|
|
96
123
|
|
97
124
|
private
|
98
125
|
|
126
|
+
# create temporary filename for UNIX Domain Socket and spawn JavaScript runtime process
|
127
|
+
# @return [[Integer, String]] [runtime_pid, socket_path]
|
128
|
+
def initialize_process
|
129
|
+
runtime_pid = 0
|
130
|
+
socket_path = ''
|
131
|
+
Dir::Tmpname.create 'execjs_pcruntime' do |path|
|
132
|
+
# Dir::Tmpname.create rescues Errno::EEXIST and retry block
|
133
|
+
# So, raise it if failed to create Process.
|
134
|
+
runtime_pid = create_process(path, *@binary, @initial_source_path) || raise(Errno::EEXIST)
|
135
|
+
socket_path = path
|
136
|
+
end
|
137
|
+
[runtime_pid, socket_path]
|
138
|
+
end
|
139
|
+
|
99
140
|
# Attempt to execute the block several times, spacing out the attempts over a certain period.
|
100
141
|
# @param [Integer] times maximum number of attempts
|
101
142
|
# @yieldreturn [Boolean] true iff succeed execute
|
@@ -148,6 +189,7 @@ module ExecJS
|
|
148
189
|
# so suppressing lint errors.
|
149
190
|
# rubocop:disable Metrics/MethodLength,Metrics/AbcSize
|
150
191
|
def post_request(socket_path, path, content_type = nil, body = nil)
|
192
|
+
@semaphore.acquire
|
151
193
|
socket = create_socket socket_path
|
152
194
|
|
153
195
|
# timeout occurred during the test
|
@@ -187,10 +229,15 @@ module ExecJS
|
|
187
229
|
error.set_backtrace(stack)
|
188
230
|
raise error
|
189
231
|
end
|
232
|
+
ensure
|
233
|
+
@semaphore.release
|
190
234
|
end
|
235
|
+
|
191
236
|
# rubocop:enable Metrics/MethodLength,Metrics/AbcSize
|
192
237
|
end
|
193
238
|
|
239
|
+
# rubocop:enable Metrics/ClassLength
|
240
|
+
|
194
241
|
attr_reader :name
|
195
242
|
|
196
243
|
# @param [String] name name of Runtime
|
@@ -203,6 +250,8 @@ module ExecJS
|
|
203
250
|
@runner_path = runner_path
|
204
251
|
@binary = nil
|
205
252
|
@deprecated = deprecated
|
253
|
+
# limit number of threads 128 to avoid Errno::ECONNREFUSED
|
254
|
+
@semaphore = Semaphore.new 128
|
206
255
|
end
|
207
256
|
|
208
257
|
# implementation of ExecJS::Runtime#available?
|
@@ -217,8 +266,8 @@ module ExecJS
|
|
217
266
|
|
218
267
|
# Launch JavaScript Runtime and return its handle.
|
219
268
|
# @return [JSRuntimeHandle]
|
220
|
-
def create_runtime_handle
|
221
|
-
JSRuntimeHandle.new(binary, @runner_path)
|
269
|
+
def create_runtime_handle(compile_source)
|
270
|
+
JSRuntimeHandle.new(binary, @runner_path, compile_source, @semaphore)
|
222
271
|
end
|
223
272
|
|
224
273
|
private
|
@@ -256,5 +305,26 @@ module ExecJS
|
|
256
305
|
nil
|
257
306
|
end
|
258
307
|
end
|
308
|
+
|
309
|
+
# Semaphore
|
310
|
+
# implemented with Thread::Queue
|
311
|
+
# since faster than Concurrent::Semaphore and Mutex+ConditionVariable
|
312
|
+
class Semaphore
|
313
|
+
# @param [Integer] limit
|
314
|
+
def initialize(limit)
|
315
|
+
@queue = Thread::Queue.new
|
316
|
+
limit.times { @queue.push nil }
|
317
|
+
end
|
318
|
+
|
319
|
+
# acquires 1 of permits from this semaphore, blocking until be available.
|
320
|
+
def acquire
|
321
|
+
@queue.pop
|
322
|
+
end
|
323
|
+
|
324
|
+
# releases 1 of permits
|
325
|
+
def release
|
326
|
+
@queue.push nil
|
327
|
+
end
|
328
|
+
end
|
259
329
|
end
|
260
330
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: execjs-pcruntime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- White-Green
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: execjs
|