ominfra 0.0.0.dev137__py3-none-any.whl → 0.0.0.dev138__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
ominfra/pyremote.py CHANGED
@@ -5,7 +5,6 @@ Basically this: https://mitogen.networkgenomics.com/howitworks.html
5
5
  """
6
6
  import base64
7
7
  import dataclasses as dc
8
- import inspect
9
8
  import json
10
9
  import os
11
10
  import platform
@@ -13,7 +12,6 @@ import pwd
13
12
  import site
14
13
  import struct
15
14
  import sys
16
- import textwrap
17
15
  import typing as ta
18
16
  import zlib
19
17
 
@@ -21,11 +19,120 @@ import zlib
21
19
  ##
22
20
 
23
21
 
22
+ @dc.dataclass(frozen=True)
23
+ class PyremoteBootstrapOptions:
24
+ debug: bool = False
25
+
26
+
27
+ ##
28
+
29
+
30
+ @dc.dataclass(frozen=True)
31
+ class PyremoteEnvInfo:
32
+ sys_base_prefix: str
33
+ sys_byteorder: str
34
+ sys_defaultencoding: str
35
+ sys_exec_prefix: str
36
+ sys_executable: str
37
+ sys_implementation_name: str
38
+ sys_path: ta.List[str]
39
+ sys_platform: str
40
+ sys_prefix: str
41
+ sys_version: str
42
+ sys_version_info: ta.List[ta.Union[int, str]]
43
+
44
+ platform_architecture: ta.List[str]
45
+ platform_machine: str
46
+ platform_platform: str
47
+ platform_processor: str
48
+ platform_system: str
49
+ platform_release: str
50
+ platform_version: str
51
+
52
+ site_userbase: str
53
+
54
+ os_cwd: str
55
+ os_gid: int
56
+ os_loadavg: ta.List[float]
57
+ os_login: ta.Optional[str]
58
+ os_pgrp: int
59
+ os_pid: int
60
+ os_ppid: int
61
+ os_uid: int
62
+
63
+ pw_name: str
64
+ pw_uid: int
65
+ pw_gid: int
66
+ pw_gecos: str
67
+ pw_dir: str
68
+ pw_shell: str
69
+
70
+ env_path: ta.Optional[str]
71
+
72
+
73
+ def _get_pyremote_env_info() -> PyremoteEnvInfo:
74
+ os_uid = os.getuid()
75
+
76
+ pw = pwd.getpwuid(os_uid)
77
+
78
+ os_login: ta.Optional[str]
79
+ try:
80
+ os_login = os.getlogin()
81
+ except OSError:
82
+ os_login = None
83
+
84
+ return PyremoteEnvInfo(
85
+ sys_base_prefix=sys.base_prefix,
86
+ sys_byteorder=sys.byteorder,
87
+ sys_defaultencoding=sys.getdefaultencoding(),
88
+ sys_exec_prefix=sys.exec_prefix,
89
+ sys_executable=sys.executable,
90
+ sys_implementation_name=sys.implementation.name,
91
+ sys_path=sys.path,
92
+ sys_platform=sys.platform,
93
+ sys_prefix=sys.prefix,
94
+ sys_version=sys.version,
95
+ sys_version_info=list(sys.version_info),
96
+
97
+ platform_architecture=list(platform.architecture()),
98
+ platform_machine=platform.machine(),
99
+ platform_platform=platform.platform(),
100
+ platform_processor=platform.processor(),
101
+ platform_system=platform.system(),
102
+ platform_release=platform.release(),
103
+ platform_version=platform.version(),
104
+
105
+ site_userbase=site.getuserbase(),
106
+
107
+ os_cwd=os.getcwd(),
108
+ os_gid=os.getgid(),
109
+ os_loadavg=list(os.getloadavg()),
110
+ os_login=os_login,
111
+ os_pgrp=os.getpgrp(),
112
+ os_pid=os.getpid(),
113
+ os_ppid=os.getppid(),
114
+ os_uid=os_uid,
115
+
116
+ pw_name=pw.pw_name,
117
+ pw_uid=pw.pw_uid,
118
+ pw_gid=pw.pw_gid,
119
+ pw_gecos=pw.pw_gecos,
120
+ pw_dir=pw.pw_dir,
121
+ pw_shell=pw.pw_shell,
122
+
123
+ env_path=os.environ.get('PATH'),
124
+ )
125
+
126
+
127
+ ##
128
+
129
+
24
130
  _PYREMOTE_BOOTSTRAP_INPUT_FD = 100
25
131
  _PYREMOTE_BOOTSTRAP_SRC_FD = 101
26
132
 
27
133
  _PYREMOTE_BOOTSTRAP_CHILD_PID_VAR = '_OPYR_CHILD_PID'
28
134
  _PYREMOTE_BOOTSTRAP_ARGV0_VAR = '_OPYR_ARGV0'
135
+ _PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR = '_OPYR_OPTIONS_JSON'
29
136
 
30
137
  _PYREMOTE_BOOTSTRAP_ACK0 = b'OPYR000\n'
31
138
  _PYREMOTE_BOOTSTRAP_ACK1 = b'OPYR001\n'
@@ -87,7 +194,9 @@ def _pyremote_bootstrap_main(context_name: str) -> None:
87
194
 
88
195
  # Read main src from stdin
89
196
  main_z_len = struct.unpack('<I', os.read(0, 4))[0]
90
- main_src = zlib.decompress(os.fdopen(0, 'rb').read(main_z_len))
197
+ if len(main_z := os.fdopen(0, 'rb').read(main_z_len)) != main_z_len:
198
+ raise EOFError
199
+ main_src = zlib.decompress(main_z)
91
200
 
92
201
  # Write both copies of main src. Must write to w0 (parent stdin) before w1 (copy pipe) as pipe will likely fill
93
202
  # and block and need to be drained by pyremote_bootstrap_finalize running in parent.
@@ -110,6 +219,8 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
110
219
  if any(c in context_name for c in '\'"'):
111
220
  raise NameError(context_name)
112
221
 
222
+ import inspect
223
+ import textwrap
113
224
  bs_src = textwrap.dedent(inspect.getsource(_pyremote_bootstrap_main))
114
225
 
115
226
  for gl in [
@@ -136,9 +247,6 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
136
247
  bs_z = zlib.compress(bs_src.encode('utf-8'))
137
248
  bs_z64 = base64.encodebytes(bs_z).replace(b'\n', b'')
138
249
 
139
- def dq_repr(o: ta.Any) -> str:
140
- return '"' + repr(o)[1:-1] + '"'
141
-
142
250
  stmts = [
143
251
  f'import {", ".join(_PYREMOTE_BOOTSTRAP_IMPORTS)}',
144
252
  f'exec(zlib.decompress(base64.decodebytes({bs_z64!r})))',
@@ -153,99 +261,83 @@ def pyremote_build_bootstrap_cmd(context_name: str) -> str:
153
261
 
154
262
 
155
263
  @dc.dataclass(frozen=True)
156
- class PyremoteEnvInfo:
157
- sys_base_prefix: str
158
- sys_byteorder: str
159
- sys_defaultencoding: str
160
- sys_exec_prefix: str
161
- sys_executable: str
162
- sys_implementation_name: str
163
- sys_path: ta.List[str]
164
- sys_platform: str
165
- sys_prefix: str
166
- sys_version: str
167
- sys_version_info: ta.List[ta.Union[int, str]]
168
-
169
- platform_architecture: ta.List[str]
170
- platform_machine: str
171
- platform_platform: str
172
- platform_processor: str
173
- platform_system: str
174
- platform_release: str
175
- platform_version: str
176
-
177
- site_userbase: str
178
-
179
- os_cwd: str
180
- os_gid: int
181
- os_loadavg: ta.List[float]
182
- os_login: ta.Optional[str]
183
- os_pgrp: int
184
- os_pid: int
185
- os_ppid: int
186
- os_uid: int
187
-
188
- pw_name: str
189
- pw_uid: int
190
- pw_gid: int
191
- pw_gecos: str
192
- pw_dir: str
193
- pw_shell: str
194
-
195
- env_path: ta.Optional[str]
264
+ class PyremotePayloadRuntime:
265
+ input: ta.BinaryIO
266
+ output: ta.BinaryIO
267
+ main_src: str
268
+ options: PyremoteBootstrapOptions
269
+ env_info: PyremoteEnvInfo
196
270
 
197
271
 
198
- def _get_pyremote_env_info() -> PyremoteEnvInfo:
199
- os_uid = os.getuid()
272
+ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
273
+ # If json options var is not present we need to do initial finalization
274
+ if _PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR not in os.environ:
275
+ # Read second copy of main src
276
+ r1 = os.fdopen(_PYREMOTE_BOOTSTRAP_SRC_FD, 'rb', 0)
277
+ main_src = r1.read().decode('utf-8')
278
+ r1.close()
279
+
280
+ # Reap boostrap child. Must be done after reading second copy of source because source may be too big to fit in
281
+ # a pipe at once.
282
+ os.waitpid(int(os.environ.pop(_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR)), 0)
283
+
284
+ # Read options
285
+ options_json_len = struct.unpack('<I', os.read(_PYREMOTE_BOOTSTRAP_INPUT_FD, 4))[0]
286
+ if len(options_json := os.read(_PYREMOTE_BOOTSTRAP_INPUT_FD, options_json_len)) != options_json_len:
287
+ raise EOFError
288
+ options = PyremoteBootstrapOptions(**json.loads(options_json.decode('utf-8')))
289
+
290
+ # If debugging, re-exec as file
291
+ if options.debug:
292
+ # Write temp source file
293
+ import tempfile
294
+ tfd, tfn = tempfile.mkstemp('-pyremote.py')
295
+ os.write(tfd, main_src.encode('utf-8'))
296
+ os.close(tfd)
297
+
298
+ # Set json options var
299
+ os.environ[_PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR] = options_json.decode('utf-8')
300
+
301
+ # Re-exec temp file
302
+ os.execl(os.environ[_PYREMOTE_BOOTSTRAP_ARGV0_VAR], sys.orig_argv[0], tfn)
200
303
 
201
- pw = pwd.getpwuid(os_uid)
304
+ else:
305
+ # Load options json var
306
+ options_json_str = os.environ.pop(_PYREMOTE_BOOTSTRAP_OPTIONS_JSON_VAR)
307
+ options = PyremoteBootstrapOptions(**json.loads(options_json_str))
202
308
 
203
- os_login: ta.Optional[str]
204
- try:
205
- os_login = os.getlogin()
206
- except OSError:
207
- os_login = None
309
+ # Read temp source file
310
+ with open(sys.orig_argv[1]) as sf:
311
+ main_src = sf.read()
208
312
 
209
- return PyremoteEnvInfo(
210
- sys_base_prefix=sys.base_prefix,
211
- sys_byteorder=sys.byteorder,
212
- sys_defaultencoding=sys.getdefaultencoding(),
213
- sys_exec_prefix=sys.exec_prefix,
214
- sys_executable=sys.executable,
215
- sys_implementation_name=sys.implementation.name,
216
- sys_path=sys.path,
217
- sys_platform=sys.platform,
218
- sys_prefix=sys.prefix,
219
- sys_version=sys.version,
220
- sys_version_info=list(sys.version_info),
313
+ # Restore original argv0
314
+ sys.executable = os.environ.pop(_PYREMOTE_BOOTSTRAP_ARGV0_VAR)
221
315
 
222
- platform_architecture=list(platform.architecture()),
223
- platform_machine=platform.machine(),
224
- platform_platform=platform.platform(),
225
- platform_processor=platform.processor(),
226
- platform_system=platform.system(),
227
- platform_release=platform.release(),
228
- platform_version=platform.version(),
316
+ # Write third ack
317
+ os.write(1, _PYREMOTE_BOOTSTRAP_ACK2)
229
318
 
230
- site_userbase=site.getuserbase(),
319
+ # Write env info
320
+ env_info = _get_pyremote_env_info()
321
+ env_info_json = json.dumps(dc.asdict(env_info), indent=None, separators=(',', ':')) # noqa
322
+ os.write(1, struct.pack('<I', len(env_info_json)))
323
+ os.write(1, env_info_json.encode('utf-8'))
231
324
 
232
- os_cwd=os.getcwd(),
233
- os_gid=os.getgid(),
234
- os_loadavg=list(os.getloadavg()),
235
- os_login=os_login,
236
- os_pgrp=os.getpgrp(),
237
- os_pid=os.getpid(),
238
- os_ppid=os.getppid(),
239
- os_uid=os_uid,
325
+ # Setup IO
326
+ input = os.fdopen(_PYREMOTE_BOOTSTRAP_INPUT_FD, 'rb', 0) # noqa
327
+ output = os.fdopen(os.dup(1), 'wb', 0) # noqa
328
+ os.dup2(nfd := os.open('/dev/null', os.O_WRONLY), 1)
329
+ os.close(nfd)
240
330
 
241
- pw_name=pw.pw_name,
242
- pw_uid=pw.pw_uid,
243
- pw_gid=pw.pw_gid,
244
- pw_gecos=pw.pw_gecos,
245
- pw_dir=pw.pw_dir,
246
- pw_shell=pw.pw_shell,
331
+ # Write fourth ack
332
+ output.write(_PYREMOTE_BOOTSTRAP_ACK3)
247
333
 
248
- env_path=os.environ.get('PATH'),
334
+ # Return
335
+ return PyremotePayloadRuntime(
336
+ input=input,
337
+ output=output,
338
+ main_src=main_src,
339
+ options=options,
340
+ env_info=env_info,
249
341
  )
250
342
 
251
343
 
@@ -253,12 +345,15 @@ def _get_pyremote_env_info() -> PyremoteEnvInfo:
253
345
 
254
346
 
255
347
  class PyremoteBootstrapDriver:
256
- def __init__(self, main_src: str) -> None:
348
+ def __init__(self, main_src: str, options: PyremoteBootstrapOptions = PyremoteBootstrapOptions()) -> None:
257
349
  super().__init__()
258
350
 
259
351
  self._main_src = main_src
260
352
  self._main_z = zlib.compress(main_src.encode('utf-8'))
261
353
 
354
+ self._options = options
355
+ self._options_json = json.dumps(dc.asdict(options), indent=None, separators=(',', ':')).encode('utf-8') # noqa
356
+
262
357
  #
263
358
 
264
359
  @dc.dataclass(frozen=True)
@@ -278,7 +373,7 @@ class PyremoteBootstrapDriver:
278
373
  env_info: PyremoteEnvInfo
279
374
 
280
375
  def gen(self) -> ta.Generator[ta.Union[Read, Write], ta.Optional[bytes], Result]:
281
- # Read first ack
376
+ # Read first ack (after fork)
282
377
  yield from self._expect(_PYREMOTE_BOOTSTRAP_ACK0)
283
378
 
284
379
  # Read pid
@@ -289,8 +384,14 @@ class PyremoteBootstrapDriver:
289
384
  yield from self._write(struct.pack('<I', len(self._main_z)))
290
385
  yield from self._write(self._main_z)
291
386
 
292
- # Read second and third ack
387
+ # Read second ack (after writing src copies)
293
388
  yield from self._expect(_PYREMOTE_BOOTSTRAP_ACK1)
389
+
390
+ # Write options
391
+ yield from self._write(struct.pack('<I', len(self._options_json)))
392
+ yield from self._write(self._options_json)
393
+
394
+ # Read third ack (after reaping child process)
294
395
  yield from self._expect(_PYREMOTE_BOOTSTRAP_ACK2)
295
396
 
296
397
  # Read env info
@@ -300,7 +401,7 @@ class PyremoteBootstrapDriver:
300
401
  env_info_json = d.decode('utf-8')
301
402
  env_info = PyremoteEnvInfo(**json.loads(env_info_json))
302
403
 
303
- # Read fourth ack
404
+ # Read fourth ack (after finalization completed)
304
405
  yield from self._expect(_PYREMOTE_BOOTSTRAP_ACK3)
305
406
 
306
407
  # Return
@@ -343,61 +444,11 @@ class PyremoteBootstrapDriver:
343
444
  return e.value
344
445
 
345
446
  if isinstance(go, self.Read):
346
- gi = stdout.read(go.sz)
447
+ if len(gi := stdout.read(go.sz)) != go.sz:
448
+ raise EOFError
347
449
  elif isinstance(go, self.Write):
348
450
  gi = None
349
451
  stdin.write(go.d)
350
452
  stdin.flush()
351
453
  else:
352
454
  raise TypeError(go)
353
-
354
-
355
- ##
356
-
357
-
358
- @dc.dataclass(frozen=True)
359
- class PyremotePayloadRuntime:
360
- input: ta.BinaryIO
361
- output: ta.BinaryIO
362
- main_src: str
363
- env_info: PyremoteEnvInfo
364
-
365
-
366
- def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
367
- # Restore original argv0
368
- sys.executable = os.environ.pop(_PYREMOTE_BOOTSTRAP_ARGV0_VAR)
369
-
370
- # Read second copy of main src
371
- r1 = os.fdopen(_PYREMOTE_BOOTSTRAP_SRC_FD, 'rb', 0)
372
- main_src = r1.read().decode('utf-8')
373
- r1.close()
374
-
375
- # Reap boostrap child. Must be done after reading second copy of source because source may be too big to fit in a
376
- # pipe at once.
377
- os.waitpid(int(os.environ.pop(_PYREMOTE_BOOTSTRAP_CHILD_PID_VAR)), 0)
378
-
379
- # Write third ack
380
- os.write(1, _PYREMOTE_BOOTSTRAP_ACK2)
381
-
382
- # Write env info
383
- env_info = _get_pyremote_env_info()
384
- env_info_json = json.dumps(dc.asdict(env_info), indent=None, separators=(',', ':')) # noqa
385
- os.write(1, struct.pack('<I', len(env_info_json)))
386
- os.write(1, env_info_json.encode('utf-8'))
387
-
388
- # Setup IO
389
- input = os.fdopen(_PYREMOTE_BOOTSTRAP_INPUT_FD, 'rb', 0) # noqa
390
- output = os.fdopen(os.dup(1), 'wb', 0) # noqa
391
- os.dup2(nfd := os.open('/dev/null', os.O_WRONLY), 1)
392
- os.close(nfd)
393
-
394
- # Write fourth ack
395
- output.write(_PYREMOTE_BOOTSTRAP_ACK3)
396
-
397
- # Return
398
- return PyremotePayloadRuntime(
399
- input=input,
400
- output=output,
401
- main_src=main_src,
402
- env_info=env_info,
403
- )
@@ -7382,7 +7382,7 @@ class ProcessImpl(Process):
7382
7382
  self._backoff = 0 # backoff counter (to start_retries)
7383
7383
 
7384
7384
  self._exitstatus: ta.Optional[Rc] = None # status attached to dead process by finish()
7385
- self._spawn_err: ta.Optional[str] = None # error message attached by spawn() if any
7385
+ self._spawn_err: ta.Optional[str] = None # error message attached by _spawn() if any
7386
7386
 
7387
7387
  #
7388
7388
 
@@ -7419,12 +7419,12 @@ class ProcessImpl(Process):
7419
7419
 
7420
7420
  #
7421
7421
 
7422
- def spawn(self) -> ta.Optional[Pid]:
7422
+ def _spawn(self) -> ta.Optional[Pid]:
7423
7423
  if self.pid:
7424
7424
  log.warning('process \'%s\' already running', self.name)
7425
7425
  return None
7426
7426
 
7427
- self.check_in_state(
7427
+ self._check_in_state(
7428
7428
  ProcessState.EXITED,
7429
7429
  ProcessState.FATAL,
7430
7430
  ProcessState.BACKOFF,
@@ -7439,15 +7439,15 @@ class ProcessImpl(Process):
7439
7439
 
7440
7440
  self._last_start = time.time()
7441
7441
 
7442
- self.change_state(ProcessState.STARTING)
7442
+ self._change_state(ProcessState.STARTING)
7443
7443
 
7444
7444
  try:
7445
7445
  sp = self._spawning.spawn()
7446
7446
  except ProcessSpawnError as err:
7447
7447
  log.exception('Spawn error')
7448
7448
  self._spawn_err = err.args[0]
7449
- self.check_in_state(ProcessState.STARTING)
7450
- self.change_state(ProcessState.BACKOFF)
7449
+ self._check_in_state(ProcessState.STARTING)
7450
+ self._change_state(ProcessState.BACKOFF)
7451
7451
  return None
7452
7452
 
7453
7453
  log.info("Spawned: '%s' with pid %s", self.name, sp.pid)
@@ -7480,7 +7480,7 @@ class ProcessImpl(Process):
7480
7480
 
7481
7481
  #
7482
7482
 
7483
- def change_state(self, new_state: ProcessState, expected: bool = True) -> bool:
7483
+ def _change_state(self, new_state: ProcessState, expected: bool = True) -> bool:
7484
7484
  old_state = self._state
7485
7485
  if new_state is old_state:
7486
7486
  return False
@@ -7498,7 +7498,7 @@ class ProcessImpl(Process):
7498
7498
 
7499
7499
  return True
7500
7500
 
7501
- def check_in_state(self, *states: ProcessState) -> None:
7501
+ def _check_in_state(self, *states: ProcessState) -> None:
7502
7502
  if self._state not in states:
7503
7503
  raise ProcessStateError(
7504
7504
  f'Check failed for {self._config.name}: '
@@ -7507,7 +7507,7 @@ class ProcessImpl(Process):
7507
7507
 
7508
7508
  #
7509
7509
 
7510
- def _check_and_adjust_for_system_clock_rollback(self, test_time):
7510
+ def _check_and_adjust_for_system_clock_rollback(self, test_time: float) -> None:
7511
7511
  """
7512
7512
  Check if system clock has rolled backward beyond test_time. If so, set affected timestamps to test_time.
7513
7513
  """
@@ -7551,8 +7551,8 @@ class ProcessImpl(Process):
7551
7551
  self._delay = 0
7552
7552
  self._backoff = 0
7553
7553
  self._system_stop = True
7554
- self.check_in_state(ProcessState.BACKOFF)
7555
- self.change_state(ProcessState.FATAL)
7554
+ self._check_in_state(ProcessState.BACKOFF)
7555
+ self._change_state(ProcessState.FATAL)
7556
7556
 
7557
7557
  def kill(self, sig: int) -> ta.Optional[str]:
7558
7558
  """
@@ -7562,6 +7562,7 @@ class ProcessImpl(Process):
7562
7562
  Return None if the signal was sent, or an error message string if an error occurred or if the subprocess is not
7563
7563
  running.
7564
7564
  """
7565
+
7565
7566
  now = time.time()
7566
7567
 
7567
7568
  # If the process is in BACKOFF and we want to stop or kill it, then BACKOFF -> STOPPED. This is needed because
@@ -7569,7 +7570,7 @@ class ProcessImpl(Process):
7569
7570
  # blocked for a long time waiting for the retries.
7570
7571
  if self._state == ProcessState.BACKOFF:
7571
7572
  log.debug('Attempted to kill %s, which is in BACKOFF state.', self.name)
7572
- self.change_state(ProcessState.STOPPED)
7573
+ self._change_state(ProcessState.STOPPED)
7573
7574
  return None
7574
7575
 
7575
7576
  args: tuple
@@ -7594,8 +7595,8 @@ class ProcessImpl(Process):
7594
7595
  self._killing = True
7595
7596
  self._delay = now + self._config.stop_wait_secs
7596
7597
  # we will already be in the STOPPING state if we're doing a SIGKILL as a result of overrunning stop_wait_secs
7597
- self.check_in_state(ProcessState.RUNNING, ProcessState.STARTING, ProcessState.STOPPING)
7598
- self.change_state(ProcessState.STOPPING)
7598
+ self._check_in_state(ProcessState.RUNNING, ProcessState.STARTING, ProcessState.STOPPING)
7599
+ self._change_state(ProcessState.STOPPING)
7599
7600
 
7600
7601
  kpid = int(self.pid)
7601
7602
  if kill_as_group:
@@ -7616,7 +7617,7 @@ class ProcessImpl(Process):
7616
7617
  tb = traceback.format_exc()
7617
7618
  fmt, args = 'unknown problem killing %s (%s):%s', (self.name, self.pid, tb)
7618
7619
  log.critical(fmt, *args)
7619
- self.change_state(ProcessState.UNKNOWN)
7620
+ self._change_state(ProcessState.UNKNOWN)
7620
7621
  self._killing = False
7621
7622
  self._delay = 0
7622
7623
  return fmt % args
@@ -7638,7 +7639,7 @@ class ProcessImpl(Process):
7638
7639
 
7639
7640
  log.debug('sending %s (pid %s) sig %s', self.name, self.pid, sig_name(sig))
7640
7641
 
7641
- self.check_in_state(ProcessState.RUNNING, ProcessState.STARTING, ProcessState.STOPPING)
7642
+ self._check_in_state(ProcessState.RUNNING, ProcessState.STARTING, ProcessState.STOPPING)
7642
7643
 
7643
7644
  try:
7644
7645
  try:
@@ -7659,7 +7660,7 @@ class ProcessImpl(Process):
7659
7660
  tb = traceback.format_exc()
7660
7661
  fmt, args = 'unknown problem sending sig %s (%s):%s', (self.name, self.pid, tb)
7661
7662
  log.critical(fmt, *args)
7662
- self.change_state(ProcessState.UNKNOWN)
7663
+ self._change_state(ProcessState.UNKNOWN)
7663
7664
  return fmt % args
7664
7665
 
7665
7666
  return None
@@ -7697,8 +7698,8 @@ class ProcessImpl(Process):
7697
7698
  self._exitstatus = Rc(es)
7698
7699
 
7699
7700
  fmt, args = 'stopped: %s (%s)', (self.name, msg)
7700
- self.check_in_state(ProcessState.STOPPING)
7701
- self.change_state(ProcessState.STOPPED)
7701
+ self._check_in_state(ProcessState.STOPPING)
7702
+ self._change_state(ProcessState.STOPPED)
7702
7703
  if exit_expected:
7703
7704
  log.info(fmt, *args)
7704
7705
  else:
@@ -7708,8 +7709,8 @@ class ProcessImpl(Process):
7708
7709
  # the program did not stay up long enough to make it to RUNNING implies STARTING -> BACKOFF
7709
7710
  self._exitstatus = None
7710
7711
  self._spawn_err = 'Exited too quickly (process log may have details)'
7711
- self.check_in_state(ProcessState.STARTING)
7712
- self.change_state(ProcessState.BACKOFF)
7712
+ self._check_in_state(ProcessState.STARTING)
7713
+ self._change_state(ProcessState.BACKOFF)
7713
7714
  log.warning('exited: %s (%s)', self.name, msg + '; not expected')
7714
7715
 
7715
7716
  else:
@@ -7722,18 +7723,18 @@ class ProcessImpl(Process):
7722
7723
  # if the process was STARTING but a system time change causes self.last_start to be in the future, the
7723
7724
  # normal STARTING->RUNNING transition can be subverted so we perform the transition here.
7724
7725
  if self._state == ProcessState.STARTING:
7725
- self.change_state(ProcessState.RUNNING)
7726
+ self._change_state(ProcessState.RUNNING)
7726
7727
 
7727
- self.check_in_state(ProcessState.RUNNING)
7728
+ self._check_in_state(ProcessState.RUNNING)
7728
7729
 
7729
7730
  if exit_expected:
7730
7731
  # expected exit code
7731
- self.change_state(ProcessState.EXITED, expected=True)
7732
+ self._change_state(ProcessState.EXITED, expected=True)
7732
7733
  log.info('exited: %s (%s)', self.name, msg + '; expected')
7733
7734
  else:
7734
7735
  # unexpected exit code
7735
7736
  self._spawn_err = f'Bad exit code {es}'
7736
- self.change_state(ProcessState.EXITED, expected=False)
7737
+ self._change_state(ProcessState.EXITED, expected=False)
7737
7738
  log.warning('exited: %s (%s)', self.name, msg + '; not expected')
7738
7739
 
7739
7740
  self._pid = Pid(0)
@@ -7753,21 +7754,21 @@ class ProcessImpl(Process):
7753
7754
  if self._config.auto_restart:
7754
7755
  if self._config.auto_restart is RestartUnconditionally:
7755
7756
  # EXITED -> STARTING
7756
- self.spawn()
7757
+ self._spawn()
7757
7758
  elif self._exitstatus not in self._config.exitcodes:
7758
7759
  # EXITED -> STARTING
7759
- self.spawn()
7760
+ self._spawn()
7760
7761
 
7761
7762
  elif state == ProcessState.STOPPED and not self._last_start:
7762
7763
  if self._config.auto_start:
7763
7764
  # STOPPED -> STARTING
7764
- self.spawn()
7765
+ self._spawn()
7765
7766
 
7766
7767
  elif state == ProcessState.BACKOFF:
7767
7768
  if self._backoff <= self._config.start_retries:
7768
7769
  if now > self._delay:
7769
7770
  # BACKOFF -> STARTING
7770
- self.spawn()
7771
+ self._spawn()
7771
7772
 
7772
7773
  if state == ProcessState.STARTING:
7773
7774
  if now - self._last_start > self._config.start_secs:
@@ -7775,8 +7776,8 @@ class ProcessImpl(Process):
7775
7776
  # proc.config.start_secs,
7776
7777
  self._delay = 0
7777
7778
  self._backoff = 0
7778
- self.check_in_state(ProcessState.STARTING)
7779
- self.change_state(ProcessState.RUNNING)
7779
+ self._check_in_state(ProcessState.STARTING)
7780
+ self._change_state(ProcessState.RUNNING)
7780
7781
  msg = ('entered RUNNING state, process has stayed up for > than %s seconds (start_secs)' % self._config.start_secs) # noqa
7781
7782
  log.info('success: %s %s', self.name, msg)
7782
7783