1
1
<?php declare (strict_types=1 );
2
2
/**
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
4
4
* the results back to the domserver.
5
5
*
6
6
* Part of the DOMjudge Programming Contest Jury System and licensed
@@ -89,19 +89,26 @@ function close_curl_handles(): void
89
89
}
90
90
}
91
91
92
+ // $lastrequest is used to avoid spamming the log with irrelevant log messages.
93
+ $ lastrequest = '' ;
94
+
92
95
/**
93
96
* Perform a request to the REST API and handle any errors.
97
+ *
94
98
* $url is the part appended to the base DOMjudge $resturl.
95
99
* $verb is the HTTP method to use: GET, POST, PUT, or DELETE
96
100
* $data is the urlencoded data passed as GET or POST parameters.
101
+ *
97
102
* When $failonerror is set to false, any error will be turned into a
98
103
* warning and null is returned.
99
- * This function retries request on transient network errors.
104
+ *
105
+ * This function retries requests on transient network errors.
100
106
* 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).
103
111
*/
104
- $ lastrequest = '' ;
105
112
function request (string $ url , string $ verb = 'GET ' , $ data = '' , bool $ failonerror = true )
106
113
{
107
114
global $ endpoints , $ endpointID , $ lastrequest ;
@@ -155,6 +162,7 @@ function request(string $url, string $verb = 'GET', $data = '', bool $failonerro
155
162
if ($ status == 401 ) {
156
163
$ errstr = "Authentication failed (error $ status) while contacting $ url. " .
157
164
"Check credentials in restapi.secret. " ;
165
+ // Do not retry on authentication failures.
158
166
break ;
159
167
} elseif ($ status < 200 || $ status >= 300 ) {
160
168
$ json = dj_json_try_decode ($ response );
@@ -213,21 +221,27 @@ function djconfig_refresh(): void
213
221
}
214
222
215
223
/**
216
- * Retrieve a value from the DOMjudge configuration.
224
+ * Retrieve a specific value from the DOMjudge configuration.
217
225
*/
218
226
function djconfig_get_value (string $ name )
219
227
{
220
228
global $ domjudge_config ;
221
229
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. " );
223
235
}
224
236
return $ domjudge_config [$ name ];
225
237
}
226
238
227
239
/**
228
240
* Encode file contents for POST-ing to REST API.
241
+ *
229
242
* Returns contents of $file (optionally limited in size, see
230
243
* dj_file_get_contents) as encoded string.
244
+ *
231
245
* $sizelimit can be set to the following values:
232
246
* - TRUE: use the 'output_storage_limit' configuration setting
233
247
* - positive integer: limit to this many bytes
@@ -260,23 +274,26 @@ function usage(): never
260
274
echo "Usage: " . SCRIPT_ID . " [OPTION]... \n" .
261
275
"Start the judgedaemon. \n\n" .
262
276
" -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" .
264
279
" -v <level> set verbosity to <level>; these are syslog levels: \n" .
265
280
" default is LOG_INFO = 5, max is LOG_DEBUG = 7 \n" .
266
281
" -h display this help and exit \n" .
267
282
" -V output version information and exit \n\n" ;
268
283
exit ;
269
284
}
270
285
271
- function read_judgehostlog (int $ n = 20 ) : string
286
+ function read_judgehostlog (int $ numLines = 20 ) : string
272
287
{
273
288
ob_start ();
274
- passthru ("tail -n $ n " . dj_escapeshellarg (LOGFILE ));
289
+ passthru ("tail -n $ numLines " . dj_escapeshellarg (LOGFILE ));
275
290
return trim (ob_get_clean ());
276
291
}
277
292
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.
280
297
function fetch_executable (
281
298
string $ workdirpath ,
282
299
string $ type ,
@@ -306,7 +323,7 @@ function fetch_executable(
306
323
return [$ execrunpath , $ error ];
307
324
}
308
325
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.
310
327
// Returns an array with
311
328
// - absolute path to run script (null if unsuccessful)
312
329
// - an error message (null if successful)
@@ -629,7 +646,7 @@ function fetch_executable_internal(
629
646
exit (0 );
630
647
}
631
648
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
633
650
// unprivileged user.
634
651
umask (0022 );
635
652
@@ -663,12 +680,12 @@ function fetch_executable_internal(
663
680
}
664
681
}
665
682
666
- // Constantly check API for unjudged submissions
683
+ // Constantly check API for outstanding judgetasks, cycling through all configured endpoints.
667
684
$ endpointIDs = array_keys ($ endpoints );
668
685
$ currentEndpoint = 0 ;
669
686
$ lastWorkdir = null ;
670
687
while (true ) {
671
- // If all endpoints are waiting, sleep for a bit
688
+ // If all endpoints are waiting, sleep for a bit.
672
689
$ dosleep = true ;
673
690
foreach ($ endpoints as $ id => $ endpoint ) {
674
691
if ($ endpoint ['errorred ' ]) {
@@ -681,13 +698,13 @@ function fetch_executable_internal(
681
698
break ;
682
699
}
683
700
}
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.
685
702
if ($ dosleep && $ currentEndpoint ==0 ) {
686
703
dj_sleep ($ waittime );
687
704
$ waittime = min ($ waittime *2 , MAXIMAL_WAITTIME_SEC );
688
705
}
689
706
690
- // Increment our currentEndpoint pointer
707
+ // Cycle through endpoints.
691
708
$ currentEndpoint = ($ currentEndpoint + 1 ) % count ($ endpoints );
692
709
$ endpointID = $ endpointIDs [$ currentEndpoint ];
693
710
$ workdirpath = JUDGEDIR . "/ $ myhost/endpoint- $ endpointID " ;
@@ -752,8 +769,8 @@ function fetch_executable_internal(
752
769
}
753
770
}
754
771
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.
757
774
$ row = [];
758
775
$ judging = request ('judgehosts/fetch-work ' , 'POST ' , ['hostname ' => $ myhost ], false );
759
776
// If $judging is null, an error occurred; we marked the endpoint already as errorred above.
@@ -763,7 +780,7 @@ function fetch_executable_internal(
763
780
$ row = dj_json_decode ($ judging );
764
781
}
765
782
766
- // nothing returned -> no open submissions for us
783
+ // Nothing returned -> no open work for us.
767
784
if (empty ($ row )) {
768
785
if (! $ endpoints [$ endpointID ]["waiting " ]) {
769
786
$ endpoints [$ endpointID ]["waiting " ] = true ;
@@ -1011,7 +1028,7 @@ function registerJudgehost(string $myhost): void
1011
1028
1012
1029
// Auto-register judgehost.
1013
1030
// 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.
1015
1032
$ unfinished = request ('judgehosts ' , 'POST ' , 'hostname= ' . urlencode ($ myhost ), false );
1016
1033
if ($ unfinished === null ) {
1017
1034
logmsg (LOG_WARNING , "Registering judgehost on endpoint $ endpointID failed. " );
@@ -1352,8 +1369,6 @@ function judge(array $judgeTask): bool
1352
1369
logmsg (LOG_WARNING , "Aborted judging task " . $ jud ['judgetaskid ' ] .
1353
1370
" due to signal " );
1354
1371
}
1355
-
1356
- // Break, not exit so we cleanup nicely.
1357
1372
return false ;
1358
1373
}
1359
1374
0 commit comments