11<?php declare (strict_types=1 );
22/**
3- * Request a yet unjudged submission from the domserver, judge it, and pass
3+ * Requests a batch of judge tasks the domserver, executes them and reports
44 * the results back to the domserver.
55 *
66 * Part of the DOMjudge Programming Contest Jury System and licensed
@@ -89,19 +89,26 @@ function close_curl_handles(): void
8989 }
9090}
9191
92+ // $lastrequest is used to avoid spamming the log with irrelevant log messages.
93+ $ lastrequest = '' ;
94+
9295/**
9396 * Perform a request to the REST API and handle any errors.
97+ *
9498 * $url is the part appended to the base DOMjudge $resturl.
9599 * $verb is the HTTP method to use: GET, POST, PUT, or DELETE
96100 * $data is the urlencoded data passed as GET or POST parameters.
101+ *
97102 * When $failonerror is set to false, any error will be turned into a
98103 * warning and null is returned.
99- * This function retries request on transient network errors.
104+ *
105+ * This function retries requests on transient network errors.
100106 * To deal with the transient errors while avoiding overloads,
101- * this function uses exponential backoff algorithm.
102- * Every error except HTTP 401, 500 is considered transient.
107+ * this function uses exponential backoff algorithm with jitter.
108+ *
109+ * Every error except authentication failures (HTTP 401) is
110+ * considered transient, even internal server errors (HTTP 5xx).
103111 */
104- $ lastrequest = '' ;
105112function request (string $ url , string $ verb = 'GET ' , $ data = '' , bool $ failonerror = true )
106113{
107114 global $ endpoints , $ endpointID , $ lastrequest ;
@@ -155,6 +162,7 @@ function request(string $url, string $verb = 'GET', $data = '', bool $failonerro
155162 if ($ status == 401 ) {
156163 $ errstr = "Authentication failed (error $ status) while contacting $ url. " .
157164 "Check credentials in restapi.secret. " ;
165+ // Do not retry on authentication failures.
158166 break ;
159167 } elseif ($ status < 200 || $ status >= 300 ) {
160168 $ json = dj_json_try_decode ($ response );
@@ -213,21 +221,27 @@ function djconfig_refresh(): void
213221}
214222
215223/**
216- * Retrieve a value from the DOMjudge configuration.
224+ * Retrieve a specific value from the DOMjudge configuration.
217225 */
218226function djconfig_get_value (string $ name )
219227{
220228 global $ domjudge_config ;
221229 if (empty ($ domjudge_config )) {
222- error ("DOMjudge config not initialised before call to djconfig_get_value() " );
230+ djconfig_refresh ();
231+ }
232+
233+ if (!array_key_exists ($ name , $ domjudge_config )) {
234+ error ("Configuration value ' $ name' not found in config. " );
223235 }
224236 return $ domjudge_config [$ name ];
225237}
226238
227239/**
228240 * Encode file contents for POST-ing to REST API.
241+ *
229242 * Returns contents of $file (optionally limited in size, see
230243 * dj_file_get_contents) as encoded string.
244+ *
231245 * $sizelimit can be set to the following values:
232246 * - TRUE: use the 'output_storage_limit' configuration setting
233247 * - positive integer: limit to this many bytes
@@ -260,23 +274,26 @@ function usage(): never
260274 echo "Usage: " . SCRIPT_ID . " [OPTION]... \n" .
261275 "Start the judgedaemon. \n\n" .
262276 " -n <id> bind to CPU <id> and user " . RUNUSER . "-<id> \n" .
263- " --diskspace-error send internal error on low diskspace \n" .
277+ " --diskspace-error send internal error on low diskspace; if not set, \n" .
278+ " the judgedaemon will try to clean up and continue \n" .
264279 " -v <level> set verbosity to <level>; these are syslog levels: \n" .
265280 " default is LOG_INFO = 5, max is LOG_DEBUG = 7 \n" .
266281 " -h display this help and exit \n" .
267282 " -V output version information and exit \n\n" ;
268283 exit ;
269284}
270285
271- function read_judgehostlog (int $ n = 20 ) : string
286+ function read_judgehostlog (int $ numLines = 20 ) : string
272287{
273288 ob_start ();
274- passthru ("tail -n $ n " . dj_escapeshellarg (LOGFILE ));
289+ passthru ("tail -n $ numLines " . dj_escapeshellarg (LOGFILE ));
275290 return trim (ob_get_clean ());
276291}
277292
278- // Fetches new executable from database if necessary, and runs build script to compile executable.
279- // Returns an array with absolute path to run script and possibly an error message.
293+ // Fetches a new executable from database if not cached already, and runs build script to compile executable.
294+ // Returns an array with
295+ // - absolute path to run script
296+ // - optional error message.
280297function fetch_executable (
281298 string $ workdirpath ,
282299 string $ type ,
@@ -306,7 +323,7 @@ function fetch_executable(
306323 return [$ execrunpath , $ error ];
307324}
308325
309- // Internal function to fetch new executable from database if necessary, and run build script to compile executable.
326+ // Internal function to fetch a new executable from database if necessary, and run build script to compile executable.
310327// Returns an array with
311328// - absolute path to run script (null if unsuccessful)
312329// - an error message (null if successful)
@@ -629,7 +646,7 @@ function fetch_executable_internal(
629646 exit (0 );
630647}
631648
632- // Set umask to allow group, other access, as this is needed for the
649+ // Set umask to allow group and other access, as this is needed for the
633650// unprivileged user.
634651umask (0022 );
635652
@@ -663,12 +680,12 @@ function fetch_executable_internal(
663680 }
664681}
665682
666- // Constantly check API for unjudged submissions
683+ // Constantly check API for outstanding judgetasks, cycling through all configured endpoints.
667684$ endpointIDs = array_keys ($ endpoints );
668685$ currentEndpoint = 0 ;
669686$ lastWorkdir = null ;
670687while (true ) {
671- // If all endpoints are waiting, sleep for a bit
688+ // If all endpoints are waiting, sleep for a bit.
672689 $ dosleep = true ;
673690 foreach ($ endpoints as $ id => $ endpoint ) {
674691 if ($ endpoint ['errorred ' ]) {
@@ -681,13 +698,13 @@ function fetch_executable_internal(
681698 break ;
682699 }
683700 }
684- // Sleep only if everything is "waiting" and only if we're looking at the first endpoint again
701+ // Sleep only if everything is "waiting" and only if we're looking at the first endpoint again.
685702 if ($ dosleep && $ currentEndpoint ==0 ) {
686703 dj_sleep ($ waittime );
687704 $ waittime = min ($ waittime *2 , MAXIMAL_WAITTIME_SEC );
688705 }
689706
690- // Increment our currentEndpoint pointer
707+ // Cycle through endpoints.
691708 $ currentEndpoint = ($ currentEndpoint + 1 ) % count ($ endpoints );
692709 $ endpointID = $ endpointIDs [$ currentEndpoint ];
693710 $ workdirpath = JUDGEDIR . "/ $ myhost/endpoint- $ endpointID " ;
@@ -752,8 +769,8 @@ function fetch_executable_internal(
752769 }
753770 }
754771
755- // Request open submissions to judge. Any errors will be treated as
756- // non-fatal: we will just keep on retrying in this loop.
772+ // Request open judge tasks to be executed.
773+ // Any errors will be treated as non-fatal: we will just keep on retrying in this loop.
757774 $ row = [];
758775 $ judging = request ('judgehosts/fetch-work ' , 'POST ' , ['hostname ' => $ myhost ], false );
759776 // If $judging is null, an error occurred; we marked the endpoint already as errorred above.
@@ -763,7 +780,7 @@ function fetch_executable_internal(
763780 $ row = dj_json_decode ($ judging );
764781 }
765782
766- // nothing returned -> no open submissions for us
783+ // Nothing returned -> no open work for us.
767784 if (empty ($ row )) {
768785 if (! $ endpoints [$ endpointID ]["waiting " ]) {
769786 $ endpoints [$ endpointID ]["waiting " ] = true ;
@@ -1011,7 +1028,7 @@ function registerJudgehost(string $myhost): void
10111028
10121029 // Auto-register judgehost.
10131030 // If there are any unfinished judgings in the queue in my name,
1014- // they will not be finished. Give them back.
1031+ // they have and will not be finished. Give them back.
10151032 $ unfinished = request ('judgehosts ' , 'POST ' , 'hostname= ' . urlencode ($ myhost ), false );
10161033 if ($ unfinished === null ) {
10171034 logmsg (LOG_WARNING , "Registering judgehost on endpoint $ endpointID failed. " );
@@ -1352,8 +1369,6 @@ function judge(array $judgeTask): bool
13521369 logmsg (LOG_WARNING , "Aborted judging task " . $ jud ['judgetaskid ' ] .
13531370 " due to signal " );
13541371 }
1355-
1356- // Break, not exit so we cleanup nicely.
13571372 return false ;
13581373 }
13591374
0 commit comments