Skip to content

Commit 737c734

Browse files
🐛 fix sleep timers not properly taking floats into account (#153)
1 parent 195b93c commit 737c734

7 files changed

Lines changed: 113 additions & 59 deletions

File tree

phpcs.xml

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,6 @@
2323
</properties>
2424
</rule>
2525

26-
<!-- All PHP files MUST end with a non-blank line, terminated with a single LF. -->
27-
<rule ref="PSR2.Files.EndFileNewline"/>
28-
29-
<!-- The closing ?> tag MUST be omitted from files containing only PHP. -->
30-
<rule ref="PSR2.Files.ClosingTag"/>
31-
3226
<!-- 2.3 Lines -->
3327

3428
<!--Lines SHOULD NOT be longer than 80 characters; lines longer than that SHOULD be split into multiple subsequent lines of no more than 80 characters each. -->
@@ -117,13 +111,6 @@
117111

118112
<!-- 4.1 Extends and Implements -->
119113

120-
<!-- The extends and implements keywords MUST be declared on the same line as the class name. -->
121-
<!-- The opening brace for the class MUST go on its own line; the closing brace for the class MUST go on the next line after the body. -->
122-
<!-- Opening braces MUST be on their own line and MUST NOT be preceded or followed by a blank line. -->
123-
<!-- Closing braces MUST be on their own line and MUST NOT be preceded by a blank line. -->
124-
<!-- Lists of implements and, in the case of interfaces, extends MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one interface per line. -->
125-
<!-- checked by PSR12.Classes.OpeningBraceSpace -->
126-
<rule ref="PSR2.Classes.ClassDeclaration"/>
127114

128115
<!-- 4.2 Using traits -->
129116

@@ -135,16 +122,8 @@
135122

136123
<!-- 4.3 Properties and Constants -->
137124

138-
<!-- Visibility MUST be declared on all properties. -->
139-
<!-- The var keyword MUST NOT be used to declare a property. -->
140-
<!-- There MUST NOT be more than one property declared per statement. -->
141-
<!-- Property names MUST NOT be prefixed with a single underscore to indicate protected or private visibility.
142-
That is, an underscore prefix explicitly has no meaning. -->
143-
<!-- There MUST be a space between type declaration and property name. -->
144-
<rule ref="PSR2.Classes.PropertyDeclaration"/>
145125

146-
<!-- Visibility MUST be declared on all constants if your project PHP minimum version supports constant visibilities (PHP 7.1 or later). -->
147-
<!-- checked by PSR12.Properties.ConstantVisibility -->
126+
<rule ref="PSR12.Properties.ConstantVisibility"/>
148127

149128
<!-- 4.4 Methods and Functions -->
150129

@@ -155,15 +134,6 @@
155134
<exclude name="Squiz.Commenting.FunctionComment.InvalidReturn"/>
156135
<exclude name="Squiz.Commenting.FunctionComment.IncorrectParamVarName"/>
157136

158-
<!-- Method names MUST NOT be prefixed with a single underscore to indicate protected or private visibility. That is, an underscore prefix explicitly has no meaning. -->
159-
<rule ref="PSR2.Methods.MethodDeclaration"/>
160-
<rule ref="PSR2.Methods.MethodDeclaration.Underscore">
161-
<type>error</type>
162-
<message>Method name "%s" must not be prefixed with an underscore to indicate visibility</message>
163-
</rule>
164-
165-
<!-- Method and function names MUST NOT be declared with space after the method name. The opening brace MUST go on its own line, and the closing brace MUST go on the next line following the body. There MUST NOT be a space after the opening parenthesis, and there MUST NOT be a space before the closing parenthesis. -->
166-
<rule ref="PSR2.Methods.FunctionClosingBrace"/>
167137
<rule ref="Squiz.Functions.FunctionDeclaration"/>
168138
<rule ref="Squiz.Functions.LowercaseFunctionKeywords"/>
169139

@@ -196,20 +166,12 @@
196166

197167
<!-- When present, the abstract and final declarations MUST precede the visibility declaration. -->
198168
<!-- When present, the static declaration MUST come after the visibility declaration. -->
199-
<!-- checked by PSR2.Methods.MethodDeclaration included above -->
200169

201170
<!-- 4.7 Method and Function Calls -->
202171

203172
<!-- When making a method or function call, there MUST NOT be a space between the method or function name and the opening parenthesis, there MUST NOT be a space after the opening parenthesis, and there MUST NOT be a space before the closing parenthesis. In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma. -->
204173
<!-- Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line. A single argument being split across multiple lines (as might be the case with an anonymous function or array) does not constitute splitting the argument list itself. -->
205174
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
206-
<rule ref="PSR2.Methods.FunctionCallSignature"/>
207-
<rule ref="PSR2.Methods.FunctionCallSignature.SpaceAfterCloseBracket">
208-
<severity>0</severity>
209-
</rule>
210-
<rule ref="PSR2.Methods.FunctionCallSignature.OpeningIndent">
211-
<severity>0</severity>
212-
</rule>
213175

214176
<!-- 5. Control Structures -->
215177

@@ -251,8 +213,6 @@
251213
<!-- else and elseif are on the same line as the closing brace from the earlier body. -->
252214
<!-- checked by Squiz.ControlStructures.ControlSignature included above -->
253215

254-
<!-- The keyword elseif SHOULD be used instead of else if so that all control keywords look like single words. -->
255-
<rule ref="PSR2.ControlStructures.ElseIfDeclaration"/>
256216

257217
<!-- Expressions in parentheses MAY be split across multiple lines, where each subsequent line is indented at least once. When doing so, the first condition MUST be on the next line. The closing parenthesis and opening brace MUST be placed together on their own line with one space between them. Boolean operators between conditions MUST always be at the beginning or at the end of the line, not a mix of both. -->
258218
<!-- checked by PSR12.ControlStructures.ControlStructureSpacing -->
@@ -261,9 +221,6 @@
261221

262222
<!-- 5.2 switch, case -->
263223

264-
<!-- The case statement MUST be indented once from switch, and the break keyword (or other terminating keywords) MUST be indented at the same level as the case body. There MUST be a comment such as // no break when fall-through is intentional in a non-empty case body. -->
265-
<rule ref="PSR2.ControlStructures.SwitchDeclaration"/>
266-
267224
<!-- Expressions in parentheses MAY be split across multiple lines, where each subsequent line is indented at least once. When doing so, the first condition MUST be on the next line. The closing parenthesis and opening brace MUST be placed together on their own line with one space between them. Boolean operators between conditions MUST always be at the beginning or at the end of the line, not a mix of both. -->
268225
<!-- checked by PSR12.ControlStructures.ControlStructureSpacing -->
269226
<!-- checked by PSR12.ControlStructures.BooleanOperatorPlacement -->
@@ -292,14 +249,6 @@
292249

293250
<!-- 5.5 foreach -->
294251

295-
<!-- exclude these messages as they are already checked by PSR2.ControlStructures.ControlStructureSpacing -->
296-
<rule ref="Squiz.ControlStructures.ForEachLoopDeclaration.SpaceAfterOpen">
297-
<severity>0</severity>
298-
</rule>
299-
<rule ref="Squiz.ControlStructures.ForEachLoopDeclaration.SpaceBeforeClose">
300-
<severity>0</severity>
301-
</rule>
302-
303252
<!-- 5.6 try, catch, finally -->
304253

305254
<!-- 6. Operators -->

src/Client.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
*/
4444
class Client
4545
{
46+
use CustomSleepMixin;
47+
4648
/**
4749
* Default owner for API products.
4850
*
@@ -463,7 +465,7 @@ public function enqueueAndParse(
463465
);
464466
error_log("Successfully enqueued document with job id: " . $enqueueResponse->job->id);
465467

466-
sleep($asyncOptions->initialDelaySec);
468+
$this->customSleep($asyncOptions->initialDelaySec);
467469
$retryCounter = 1;
468470
$pollResults = $this->parseQueued($predictionType, $enqueueResponse->job->id, $options->endpoint);
469471

@@ -473,7 +475,7 @@ public function enqueueAndParse(
473475
}
474476
error_log("Polling server for parsing result with job id: " . $enqueueResponse->job->id);
475477
$retryCounter++;
476-
sleep($asyncOptions->delaySec);
478+
$this->customSleep($asyncOptions->delaySec);
477479
$pollResults = $this->parseQueued($predictionType, $enqueueResponse->job->id, $options->endpoint);
478480
}
479481
if ($pollResults->job->status != "completed") {
@@ -540,7 +542,7 @@ public function parseQueued(
540542
public function loadPrediction(
541543
string $predictionType,
542544
LocalResponse $localResponse
543-
) {
545+
): AsyncPredictResponse|PredictResponse {
544546
try {
545547
$json = $localResponse->toArray();
546548
if (isset($json['job'])) {

src/ClientV2.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
*/
1515
class ClientV2
1616
{
17+
use CustomSleepMixin;
18+
1719
/**
1820
* @var MindeeApiV2 Mindee API V2.
1921
*/
@@ -96,7 +98,7 @@ public function enqueueAndGetInference(
9698
$queueId = $enqueueResponse->job->id;
9799
error_log("Successfully enqueued document with job id: " . $queueId);
98100

99-
sleep($pollingOptions->initialDelaySec);
101+
$this->customSleep($pollingOptions->initialDelaySec);
100102
$retryCounter = 1;
101103
$pollResults = $this->getJob($queueId);
102104

@@ -114,7 +116,7 @@ public function enqueueAndGetInference(
114116
". Job status: " . $pollResults->job->status
115117
);
116118

117-
sleep($pollingOptions->delaySec);
119+
$this->customSleep($pollingOptions->delaySec);
118120
$pollResults = $this->getJob($queueId);
119121
$retryCounter++;
120122
}

src/CustomSleepMixin.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Mindee;
4+
5+
trait CustomSleepMixin
6+
{
7+
/**
8+
* Waits for a custom amount of time from either a float or an integer.
9+
* @param float|integer $delay Delay in seconds.
10+
* @return void
11+
*/
12+
protected static function customSleep(float|int $delay): void
13+
{
14+
if ($delay <= 0) {
15+
return;
16+
}
17+
18+
$seconds = intval($delay);
19+
$nanoseconds = abs($seconds - (float) $delay);
20+
if (
21+
strtoupper(substr(PHP_OS_FAMILY, 0, 7)) === 'WINDOWS'
22+
) {
23+
usleep(1000);
24+
}
25+
time_nanosleep($seconds, (int) ($nanoseconds * 1_000_000_000));
26+
}
27+
}

src/Parsing/Common/Job.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class Job
3737
* @var array|null Information about an error that occurred during the job processing.
3838
*/
3939
public ?array $error;
40+
4041
/**
4142
* @param array $rawResponse Raw prediction array.
4243
* @throws MindeeApiException Throws if a date is faulty.
@@ -58,7 +59,10 @@ public function __construct(array $rawResponse)
5859
}
5960
$this->id = $rawResponse['id'];
6061
$this->status = $rawResponse['status'];
61-
if (array_key_exists('available_at', $rawResponse) && $rawResponse['available_at'] !== null && strtotime($rawResponse['available_at'])) {
62+
if (
63+
array_key_exists('available_at', $rawResponse) &&
64+
$rawResponse['available_at'] !== null && strtotime($rawResponse['available_at'])
65+
) {
6266
try {
6367
$this->availableAt = new DateTimeImmutable($rawResponse['available_at']);
6468
} catch (\Exception $e) {

tests/CustomSleepMixinTest.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
use PHPUnit\Framework\TestCase;
4+
5+
/**
6+
* Custom delay tests.
7+
* Note: Timers are purposefully kept loose due to frequent CI issues.
8+
*/
9+
class CustomSleepMixinTest extends TestCase
10+
{
11+
use Mindee\CustomSleepMixin;
12+
13+
public function testCustomSleep1Second(): void {
14+
$lowerBound = 1;
15+
$upperBound = 1.1;
16+
17+
$start = microtime(true);
18+
$this->customSleep(1);
19+
$elapsed = microtime(true) - $start;
20+
$this->assertGreaterThanOrEqual($lowerBound, $elapsed);
21+
$this->assertLessThanOrEqual($upperBound, $elapsed);
22+
}
23+
24+
public function testCustomSleep0dot33Seconds(): void {
25+
$lowerBound = 0.33;
26+
$upperBound = 0.43;
27+
28+
$start = microtime(true);
29+
$this->customSleep(0.33);
30+
$elapsed = microtime(true) - $start;
31+
$this->assertGreaterThanOrEqual($lowerBound, $elapsed);
32+
$this->assertLessThanOrEqual($upperBound, $elapsed);
33+
}
34+
35+
public function testCustomSleep2Seconds(): void {
36+
$lowerBound = 2;
37+
$upperBound = 2.1;
38+
39+
$start = microtime(true);
40+
$this->customSleep(2);
41+
$elapsed = microtime(true) - $start;
42+
$this->assertGreaterThanOrEqual($lowerBound, $elapsed);
43+
$this->assertLessThanOrEqual($upperBound, $elapsed);
44+
}
45+
46+
public function testCustomSleep1dot5Seconds(): void {
47+
$lowerBound = 1.5;
48+
$upperBound = 1.6;
49+
50+
$start = microtime(true);
51+
$this->customSleep(1.5);
52+
$elapsed = microtime(true) - $start;
53+
$this->assertGreaterThanOrEqual($lowerBound, $elapsed);
54+
$this->assertLessThanOrEqual($upperBound, $elapsed);
55+
}
56+
57+
public function testCustomSleep0Seconds(): void {
58+
$start = microtime(true);
59+
$this->customSleep(0);
60+
$elapsed = microtime(true) - $start;
61+
$this->assertLessThanOrEqual(0.0001, $elapsed);
62+
}
63+
64+
public function testCustomSleepMinus1Seconds(): void {
65+
$start = microtime(true);
66+
$this->customSleep(-1);
67+
$elapsed = microtime(true) - $start;
68+
$this->assertLessThanOrEqual(0.0001, $elapsed);
69+
}
70+
}

tests/Input/URLInputSourceTestFunctional.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ protected function setUp(): void
1818
$this->client = new Client();
1919
$this->outputFilePath = (getenv('GITHUB_WORKSPACE') ?: ".") .
2020
"/tests/resources/output/";
21-
$this->referenceFilePath = "https://github.com/mindee/client-lib-test-data/blob/main/products/invoice_splitter/invoice_5p.pdf?raw=true";
21+
$this->referenceFilePath = "https://github.com/mindee/client-lib-test-data/blob/main/v1/products/invoice_splitter/invoice_5p.pdf?raw=true";
2222
}
2323

2424
public static function tearDownAfterClass(): void

0 commit comments

Comments
 (0)