mirror of
https://github.com/jlengrand/bugsink.git
synced 2026-03-10 08:01:17 +00:00
server-unified: generalize for serial/parallel approach that is not django-specific
This commit is contained in:
@@ -32,4 +32,4 @@ RUN ["bugsink-manage", "migrate", "snappea", "--database=snappea"]
|
|||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
CMD [ "bugsink-server-unified", "gunicorn", "--bind=0.0.0.0:8000", "--workers=10", "--access-logfile", "-", "bugsink.wsgi", "UNIFIED_WITH", "bugsink-runsnappea"]
|
CMD [ "bugsink-server-unified", "bugsink-manage", "check", "--deploy", "--fail-level", "WARNING", "AMP_AMP", "gunicorn", "--bind=0.0.0.0:8000", "--workers=10", "--access-logfile", "-", "bugsink.wsgi", "UNIFIED_WITH", "bugsink-runsnappea"]
|
||||||
|
|||||||
@@ -39,25 +39,20 @@ class ParentProcess:
|
|||||||
child.wait()
|
child.wait()
|
||||||
|
|
||||||
def pre_start(self):
|
def pre_start(self):
|
||||||
# I'd rather pull this out of server_unified.py, but I don't know how to do that in a way that works with
|
# I'd rather this was not needed, I don't know how to do that in a way that works with Docker: The recommended
|
||||||
# Docker: The recommended way of running CMD in a Dockerfile is to use the exec form, which doesn't allow for
|
# way of running CMD in a Dockerfile is to use the exec form, which doesn't allow for running a script that does
|
||||||
# running a script that does some setup before starting the main process, i.e. doesn't allow for '&&').
|
# some setup before starting the main process, i.e. doesn't allow for '&&'. Recommended here means: warning
|
||||||
# Recommended here means: warning about signal-handling if you choose the other form.
|
# about signal-handling if you choose the other form.
|
||||||
#
|
|
||||||
# I also don't want to introduce further arg-parsing (distinguishing between serial and parallel start) so here
|
for args in self.get_pre_start_command_args(sys.argv):
|
||||||
# we have it.
|
print("Server-unified 'pre-start' process:", " ".join(args))
|
||||||
if sys.argv[1:2] == ["NO_DEPLOY_CHECK"]:
|
proc = subprocess.run(args)
|
||||||
check = subprocess.run(["bugsink-manage", "check", "--fail-level", "WARNING"])
|
if proc.returncode != 0:
|
||||||
else:
|
sys.exit(proc.returncode)
|
||||||
check = subprocess.run(["bugsink-manage", "check", "--deploy", "--fail-level", "WARNING"])
|
|
||||||
if check.returncode != 0:
|
|
||||||
# print("Server-unified failed to start because 'bugsink-manage check' failed.") superfluous
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def start_children(self):
|
def start_children(self):
|
||||||
# Start the server
|
|
||||||
# Leaving stdout and stderr as None will make the output of the child processes be passed as our own.
|
# Leaving stdout and stderr as None will make the output of the child processes be passed as our own.
|
||||||
for args in self.parse_args():
|
for args in self.get_parallel_command_args(sys.argv):
|
||||||
try:
|
try:
|
||||||
child = subprocess.Popen(args)
|
child = subprocess.Popen(args)
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -86,14 +81,35 @@ class ParentProcess:
|
|||||||
children_are_alive = False
|
children_are_alive = False
|
||||||
self.terminate_children(except_child=child)
|
self.terminate_children(except_child=child)
|
||||||
|
|
||||||
def parse_args(self):
|
@classmethod
|
||||||
|
def get_pre_start_command_args(self, argv):
|
||||||
|
"""Splits our own arguments into a list of args for each of the pre-start commands, we split on "AMP_AMP"."""
|
||||||
|
|
||||||
|
# We don't want to pass the first argument, as that is the script name
|
||||||
|
args = argv[1:]
|
||||||
|
|
||||||
|
result = []
|
||||||
|
this = []
|
||||||
|
for arg in args:
|
||||||
|
if arg == "AMP_AMP":
|
||||||
|
# AMP_AMP serves as a terminator here, i.e. we only add-to-result when we encounter it, the last bit
|
||||||
|
# is never addeded (it will be dealt with as the set of parallel commands)
|
||||||
|
result.append(this)
|
||||||
|
this = []
|
||||||
|
else:
|
||||||
|
this.append(arg)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_parallel_command_args(self, argv):
|
||||||
"""Splits our own arguments into a list of args for each of the children each, we split on "UNIFIED_WITH"."""
|
"""Splits our own arguments into a list of args for each of the children each, we split on "UNIFIED_WITH"."""
|
||||||
|
|
||||||
# We don't want to pass the first argument, as that is the script name
|
# We don't want to pass the first argument, as that is the script name
|
||||||
args = sys.argv[1:]
|
args = argv[1:]
|
||||||
|
|
||||||
if args[:1] == ["NO_DEPLOY_CHECK"]:
|
while "AMP_AMP" in args:
|
||||||
args = args[1:]
|
args = args[args.index("AMP_AMP") + 1:]
|
||||||
|
|
||||||
result = [[]]
|
result = [[]]
|
||||||
for arg in args:
|
for arg in args:
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from .volume_based_condition import VolumeBasedCondition
|
|||||||
from .streams import (
|
from .streams import (
|
||||||
compress_with_zlib, GeneratorReader, WBITS_PARAM_FOR_GZIP, WBITS_PARAM_FOR_DEFLATE, MaxDataReader,
|
compress_with_zlib, GeneratorReader, WBITS_PARAM_FOR_GZIP, WBITS_PARAM_FOR_DEFLATE, MaxDataReader,
|
||||||
MaxDataWriter, zlib_generator, brotli_generator)
|
MaxDataWriter, zlib_generator, brotli_generator)
|
||||||
|
from .scripts.server_unified import ParentProcess
|
||||||
|
|
||||||
|
|
||||||
def apply_n(f, n, v):
|
def apply_n(f, n, v):
|
||||||
@@ -129,3 +130,59 @@ class StreamsTestCase(RegularTestCase):
|
|||||||
|
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
writer.write(b"hellohello")
|
writer.write(b"hellohello")
|
||||||
|
|
||||||
|
|
||||||
|
class ServerUnifiedTestCase(RegularTestCase):
|
||||||
|
|
||||||
|
def test_arg_parsing(self):
|
||||||
|
def _check(argv, expected_pre_start, expected_parallel):
|
||||||
|
pre_start = ParentProcess.get_pre_start_command_args(argv)
|
||||||
|
parallel = ParentProcess.get_parallel_command_args(argv)
|
||||||
|
self.assertEqual(expected_pre_start, pre_start)
|
||||||
|
self.assertEqual(expected_parallel, parallel)
|
||||||
|
|
||||||
|
_check(
|
||||||
|
# meaning: a single empty command (which would lead to a failure). It's the meaningless case anyway, so I'm
|
||||||
|
# not going to make any special-case handling for it. In other words: there must be at least one command
|
||||||
|
# (and even that is quite meaningless, since you could just run the command directly).
|
||||||
|
["script.py"],
|
||||||
|
[],
|
||||||
|
[[]],
|
||||||
|
)
|
||||||
|
|
||||||
|
_check(
|
||||||
|
["script.py", "a", "b"],
|
||||||
|
[],
|
||||||
|
[["a", "b"]],
|
||||||
|
)
|
||||||
|
|
||||||
|
_check(
|
||||||
|
["script.py", "a", "b", "UNIFIED_WITH", "c", "d", "UNIFIED_WITH", "e", "f"],
|
||||||
|
[],
|
||||||
|
[["a", "b"], ["c", "d"], ["e", "f"]],
|
||||||
|
)
|
||||||
|
|
||||||
|
_check(
|
||||||
|
["script.py", "a", "b", "AMP_AMP", "c", "d", "UNIFIED_WITH", "e", "f"],
|
||||||
|
[["a", "b"]],
|
||||||
|
[["c", "d"], ["e", "f"]],
|
||||||
|
)
|
||||||
|
|
||||||
|
_check(
|
||||||
|
["script.py", "a", "b", "UNIFIED_WITH", "c", "d", "UNIFIED_WITH", "e", "f"],
|
||||||
|
[],
|
||||||
|
[["a", "b"], ["c", "d"], ["e", "f"]],
|
||||||
|
)
|
||||||
|
|
||||||
|
_check(
|
||||||
|
["script.py", "a", "b", "AMP_AMP", "c", "d", "AMP_AMP", "e", "f"],
|
||||||
|
[["a", "b"], ["c", "d"]],
|
||||||
|
[["e", "f"]],
|
||||||
|
)
|
||||||
|
|
||||||
|
_check(
|
||||||
|
["script.py", "a", "b", "AMP_AMP", "c", "d", "AMP_AMP",
|
||||||
|
"e", "f", "UNIFIED_WITH", "g", "h", "UNIFIED_WITH", "i", "j"],
|
||||||
|
[["a", "b"], ["c", "d"]],
|
||||||
|
[["e", "f"], ["g", "h"], ["i", "j"]],
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user