Changing server script to write unbuffered to stderr and added stress-test server option

This commit is contained in:
Eric Froemling 2021-02-25 17:59:42 -06:00
parent 8ccc5eeef8
commit 2c421f5420
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
9 changed files with 137 additions and 77 deletions

View File

@ -3932,26 +3932,26 @@
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
"assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e",
"assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f",
"build/prefab/full/linux_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/61/c1/35c60d99bf4867eada2b7ad0dc19",
"build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9c/64/f43f7baf75512685ac0dce8e0f1c",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ce/75/e25f75557b05b0de2ab4a281c0de",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/32/c6/4503e9fd3e6d7a27e7e1f32f8542",
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/b7/47e4719f2aef688e62ad2f416406",
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/93/85/c5c09d5fe4e13655ccb021c44d5a",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/42/7f/46fd7611f88f659d27e827a58c8f",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3e/02/5e9b6ffdc3e242e1ddbcc67c027a",
"build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/dc/6d/0a0a41762f27f0f8cdd2a7d2c033",
"build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1d/37/11d275e939854da3e1488360d1fd",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/63/26/e9e64910b7e242129c5006234116",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8b/9c/edb852a4d5c7304e39e9618bca93",
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/22/fb/29e80f93d3899abc57854b3dbe52",
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c7/fc/4e3c1cfce367e5ace09e5bcbe9fc",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9f/ee/ec4ed4396a600c69202566f2713d",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6e/1c/0d1f8e451d24591b27f15f26a827",
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d1/79/d3cb45d123726fac04611ce103f9",
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/70/2a/a1db2d042bbe3c319b2a4bc6c395",
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f5/8c/bd7cb4286e0dadf7b29211a95560",
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4c/62/5797c0590d0128637c419f74cb67",
"build/prefab/full/linux_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/76/e4/20e36d3f74b4aba6dfbf6c1e7a3c",
"build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9f/3b/46c10e31faf30642719e8d051f51",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3c/a7/3ca43775dfe81d796bfa38473303",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/51/ec/c4ebc76cd5f17f974874bcfc7733",
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/98/f3/55d5e976bf4a5e59b7fb0e1a9049",
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9d/cf/1abae2d413903ac980e3cfd6e0e3",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1c/3c/161096b136ac519eaf7ead0d32a1",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/13/1c/c72c01e8e7ed072b2452142fca77",
"build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d6/9d/e4a6554a9712cda7840511219df2",
"build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c8/ca/e686c76cc102db57c4df20a0db04",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9a/59/c272db6020c424a96ce01a4f5d56",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8a/87/7bbc845d3559609d1b5a411d12e2",
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5b/77/f45ffd7e36bf3e86d8c8c01c5b72",
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/83/97/446ffe1f9e6a762d8f006b264654",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2b/29/785e06a7b25ed5b55a9d0e93c6bf",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c2/ef/3cade90a38e855c8dc9c15295c32",
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d6/c9/3e3a70a888a785a4f0e9dd483a1f",
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8a/1b/4fdf49299324c76e637777ea7e4a",
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/57/48/fab31e4ac7d9f846245ebaf6fe0a",
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e8/b0/841559924243fcada9d7d1cb58de",
"build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4c/bf/393694ea67f3d590dd2706c9955e",
"build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/78/cb/bb9ae4f896f862074057c8e36e1d",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ae/bd/39d7b885f7f01e81d0e96f0f85ce",
@ -3960,12 +3960,12 @@
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/52/d9/563a6949d2c4db5a915c54460fbc",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d0/6a/42fe8d2e34f95e1b3282e8422344",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/50/cf/bad44b07a4022aee3001002086b5",
"build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/bd/bc/1e305f3aafb660b0f45256fd07d1",
"build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ea/0e/42b6ec781850c69e6bab8e1b14f6",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/92/84/7e78c73d0c91d45f92f795155d5f",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b9/4e/9fe6ea82f278ace93e724253df84",
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/15/a4/7e2d2dbc870b286358d34b6e6cee",
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e3/10/4e2baf04c93a5bc632bdbd7e92f6",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/23/f4/c55e363bb00319971d21b2382431",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/27/2f/c8895ca79eb249a959578a203ff7"
"build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/38/dc/ac069b31a566df1b738adae005b6",
"build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c9/96/a75c9739a5cccca60cd74cea22ca",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/3c/17/f1b4bb490383d9dc43714f39c77b",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c2/e0/32f9701738320d592692e9b30869",
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/98/43/d779605636305318e68d4eaef10a",
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/28/b2/7ce9803bf834bf90f3d5927c323e",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/be/e4/e37e38122257176c923475c4be83",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/eb/51/2ca27968b65c54abe198ff49f164"
}

View File

@ -335,8 +335,16 @@ class ServerController:
_ba.set_public_party_stats_url(self._config.stats_url)
_ba.set_public_party_enabled(self._config.party_is_public)
# And here we go.
_ba.new_host_session(sessiontype)
# And here.. we.. go.
if self._config.stress_test_players is not None:
# Special case: run a stress test.
from ba.internal import run_stress_test
run_stress_test(playlist_type='Random',
playlist_name='__default__',
player_count=self._config.stress_test_players,
round_duration=30)
else:
_ba.new_host_session(sessiontype)
# Run an access check if we're trying to make a public party.
if not self._ran_access_check and self._config.party_is_public:

View File

@ -116,8 +116,11 @@ class ServerManagerApp:
self._running = True
dbgstr = 'debug' if __debug__ else 'opt'
print(f'{Clr.CYN}{Clr.BLD}BallisticaCore server manager {VERSION_STR}'
f' starting up ({dbgstr} mode)...{Clr.RST}')
print(
f'{Clr.CYN}{Clr.BLD}BallisticaCore server manager {VERSION_STR}'
f' starting up ({dbgstr} mode)...{Clr.RST}',
file=sys.stderr,
flush=True)
# Python will handle SIGINT for us (as KeyboardInterrupt) but we
# need to register a SIGTERM handler so we have a chance to clean
@ -136,11 +139,15 @@ class ServerManagerApp:
def _postrun(self) -> None:
"""Common code at the end of any run."""
print(f'{Clr.CYN}Server manager shutting down...{Clr.RST}')
print(f'{Clr.CYN}Server manager shutting down...{Clr.RST}',
file=sys.stderr,
flush=True)
assert self._subprocess_thread is not None
if self._subprocess_thread.is_alive():
print(f'{Clr.CYN}Waiting for subprocess exit...{Clr.RST}')
print(f'{Clr.CYN}Waiting for subprocess exit...{Clr.RST}',
file=sys.stderr,
flush=True)
# Mark ourselves as shutting down and wait for the process to wrap up.
self._done = True
@ -181,9 +188,12 @@ class ServerManagerApp:
self._prerun()
# Print basic usage info for interactive mode.
print(f"{Clr.CYN}Interactive mode enabled; use the 'mgr' object"
f' to interact with the server.\n'
f"Type 'help(mgr)' for more information.{Clr.RST}")
print(
f"{Clr.CYN}Interactive mode enabled; use the 'mgr' object"
f' to interact with the server.\n'
f"Type 'help(mgr)' for more information.{Clr.RST}",
file=sys.stderr,
flush=True)
context = {'__name__': '__console__', '__doc__': None, 'mgr': self}
@ -200,8 +210,11 @@ class ServerManagerApp:
# left in limbo with our process thread still running.
pass
except BaseException as exc:
print(f'{Clr.SRED}Unexpected interpreter exception:'
f' {exc} ({type(exc)}){Clr.RST}')
print(
f'{Clr.SRED}Unexpected interpreter exception:'
f' {exc} ({type(exc)}){Clr.RST}',
file=sys.stderr,
flush=True)
self._postrun()
@ -450,16 +463,23 @@ class ServerManagerApp:
if strict:
raise CleanError(
f'Error loading config file:\n{exc}') from exc
print(f'{Clr.RED}Error loading config file:\n{exc}.{Clr.RST}')
print(f'{Clr.RED}Error loading config file:\n{exc}.{Clr.RST}',
file=sys.stderr,
flush=True)
if trynum == maxtries - 1:
print(f'{Clr.RED}Max-tries reached; giving up.'
f' Existing config values will be used.{Clr.RST}')
print(
f'{Clr.RED}Max-tries reached; giving up.'
f' Existing config values will be used.{Clr.RST}',
file=sys.stderr,
flush=True)
break
print(
f'{Clr.CYN}Please correct the error.'
f' Will re-attempt load in {retry_seconds}'
f' seconds. (attempt {trynum+1} of {maxtries-1}).{Clr.RST}'
)
f' seconds. (attempt {trynum+1} of'
f' {maxtries-1}).{Clr.RST}',
file=sys.stderr,
flush=True)
time.sleep(1)
@ -481,9 +501,12 @@ class ServerManagerApp:
# missing.
if not self._user_provided_config_path:
if print_confirmation:
print(f'{Clr.YLW}Default config file not found'
f' (\'{self._config_path}\'); using default'
f' settings.{Clr.RST}')
print(
f'{Clr.YLW}Default config file not found'
f' (\'{self._config_path}\'); using default'
f' settings.{Clr.RST}',
file=sys.stderr,
flush=True)
self._config_mtime = None
self._last_config_mtime_check_time = time.time()
return ServerConfig()
@ -509,7 +532,9 @@ class ServerManagerApp:
out = ServerConfig()
if print_confirmation:
print(f'{Clr.CYN}Valid server config file loaded.{Clr.RST}')
print(f'{Clr.CYN}Valid server config file loaded.{Clr.RST}',
file=sys.stderr,
flush=True)
return out
def _enable_tab_completion(self, locs: Dict) -> None:
@ -552,7 +577,9 @@ class ServerManagerApp:
# slight behavior tweaks. Hmm; should this be an argument instead?
os.environ['BA_SERVER_WRAPPER_MANAGED'] = '1'
print(f'{Clr.CYN}Launching server subprocess...{Clr.RST}')
print(f'{Clr.CYN}Launching server subprocess...{Clr.RST}',
file=sys.stderr,
flush=True)
binary_name = ('ballisticacore_headless.exe'
if os.name == 'nt' else './ballisticacore_headless')
assert self._ba_root_path is not None
@ -663,7 +690,9 @@ class ServerManagerApp:
# alive.
if (self._subprocess_force_kill_time is not None
and time.time() > self._subprocess_force_kill_time):
print(f'{Clr.CYN}Force-killing subprocess...{Clr.RST}')
print(f'{Clr.CYN}Force-killing subprocess...{Clr.RST}',
file=sys.stderr,
flush=True)
break
# Watch for the server process exiting..
@ -679,8 +708,11 @@ class ServerManagerApp:
self._should_report_subprocess_error = True
clr = Clr.CYN if code == 0 else Clr.RED
print(f'{clr}Server subprocess exited'
f' with code {code}.{Clr.RST}')
print(
f'{clr}Server subprocess exited'
f' with code {code}.{Clr.RST}',
file=sys.stderr,
flush=True)
self._reset_subprocess_vars()
# Avoid super fast death loops.
@ -709,8 +741,11 @@ class ServerManagerApp:
else:
mtime = None
if mtime != self._config_mtime:
print(f'{Clr.CYN}Config-file change detected;'
f' requesting immediate restart.{Clr.RST}')
print(
f'{Clr.CYN}Config-file change detected;'
f' requesting immediate restart.{Clr.RST}',
file=sys.stderr,
flush=True)
self.restart(immediate=True)
self._subprocess_sent_config_auto_restart = True
@ -724,10 +759,13 @@ class ServerManagerApp:
if (minutes_since_launch > clean_exit_minutes
and not self._subprocess_sent_clean_exit):
opname = 'restart' if self._auto_restart else 'shutdown'
print(f'{Clr.CYN}clean_exit_minutes'
f' ({clean_exit_minutes})'
f' elapsed; requesting soft'
f' {opname}.{Clr.RST}')
print(
f'{Clr.CYN}clean_exit_minutes'
f' ({clean_exit_minutes})'
f' elapsed; requesting soft'
f' {opname}.{Clr.RST}',
file=sys.stderr,
flush=True)
if self._auto_restart:
self.restart(immediate=False)
else:
@ -744,10 +782,13 @@ class ServerManagerApp:
if (minutes_since_launch > unclean_exit_minutes
and not self._subprocess_sent_unclean_exit):
opname = 'restart' if self._auto_restart else 'shutdown'
print(f'{Clr.CYN}unclean_exit_minutes'
f' ({unclean_exit_minutes})'
f' elapsed; requesting immediate'
f' {opname}.{Clr.RST}')
print(
f'{Clr.CYN}unclean_exit_minutes'
f' ({unclean_exit_minutes})'
f' elapsed; requesting immediate'
f' {opname}.{Clr.RST}',
file=sys.stderr,
flush=True)
if self._auto_restart:
self.restart(immediate=True)
else:
@ -768,7 +809,9 @@ class ServerManagerApp:
if self._subprocess is None:
return
print(f'{Clr.CYN}Stopping subprocess...{Clr.RST}')
print(f'{Clr.CYN}Stopping subprocess...{Clr.RST}',
file=sys.stderr,
flush=True)
# First, ask it nicely to die and give it a moment.
# If that doesn't work, bring down the hammer.
@ -778,7 +821,9 @@ class ServerManagerApp:
except subprocess.TimeoutExpired:
self._subprocess.kill()
self._reset_subprocess_vars()
print(f'{Clr.CYN}Subprocess stopped.{Clr.RST}')
print(f'{Clr.CYN}Subprocess stopped.{Clr.RST}',
file=sys.stderr,
flush=True)
def main() -> None:

View File

@ -1,5 +1,5 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<h4><em>last updated on 2021-02-25 for Ballistica version 1.6.0 build 20308</em></h4>
<h4><em>last updated on 2021-02-25 for Ballistica version 1.6.0 build 20309</em></h4>
<p>This page documents the Python classes and functions in the 'ba' module,
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
<hr>

View File

@ -128,11 +128,8 @@ void App::ShutdownComplete() {
}
void App::RunEvents() {
if (!HeadlessMode()) {
// there's probably a better place for this...
// UpdateStressTesting();
stress_test_->Update();
}
// there's probably a better place for this...
stress_test_->Update();
// Give platforms a chance to pump/handle their own events.
// FIXME: now that we have app class overrides, platform should really

View File

@ -10,10 +10,13 @@ namespace ballistica {
// We could technically use the vanilla App class here since we're not
// changing anything.
HeadlessApp::HeadlessApp(Thread* thread) : App(thread) {
// NewThreadTimer(10, true, NewLambdaRunnable([this] {
// assert(g_app);
// g_app->RunEvents();
// }));
// Handle a few misc things like stress-test updates.
// (SDL builds set up a similar timer so we need to also).
// This can probably go away at some point.
NewThreadTimer(10, true, NewLambdaRunnable([this] {
assert(g_app);
g_app->RunEvents();
}));
}
} // namespace ballistica

View File

@ -21,7 +21,7 @@
namespace ballistica {
// These are set automatically via script; don't change here.
const int kAppBuildNumber = 20308;
const int kAppBuildNumber = 20310;
const char* kAppVersion = "1.6.0";
// Our standalone globals.

View File

@ -111,6 +111,9 @@ class ServerConfig:
# auto-restart is enabled (the default).
idle_exit_minutes: Optional[float] = None
# (internal) stress-testing mode.
stress_test_players: Optional[int] = None
# NOTE: as much as possible, communication from the server-manager to the
# child-process should go through these and not ad-hoc Python string commands

View File

@ -650,8 +650,11 @@ def _get_server_config_template_yaml(projroot: str) -> str:
import yaml
lines_in = _get_server_config_raw_contents(projroot).splitlines()
lines_out: List[str] = []
ignore_vars = {'stress_test_players'}
for line in lines_in:
if line != '' and not line.startswith('#'):
if (line != '' and not line.startswith('#')
and not any(line.startswith(f'{var}:')
for var in ignore_vars)):
vname, _vtype, veq, vval_raw = line.split()
assert vname.endswith(':')
vname = vname[:-1]
@ -685,7 +688,8 @@ def _get_server_config_template_yaml(projroot: str) -> str:
else:
# Convert comments referring to python bools to yaml bools.
line = line.replace('True', 'true').replace('False', 'false')
lines_out.append(line)
if '(internal)' not in line:
lines_out.append(line)
return '\n'.join(lines_out)