Add tests for handling ambiguous timeout errors and deferred relay side effects in Self-serve entrance start logic
- Introduced `SelfserveLaneStartEntranceTimeoutHarness` class and supporting tests to validate ambiguous relay timeout handling during entrance operations. - Added `defer_relay_side_effects` parameter to `selfserve_lane_command_arguments` for improved relay control during wash start. - Enhanced lane start routine to support conditional relay side effects and timeout handling with detailed logging.
This commit is contained in:
@@ -6,6 +6,7 @@ class selfserve_lane_command_arguments
|
||||
{
|
||||
public ?string $license_plate = null;
|
||||
public ?int $customer_number = null;
|
||||
public bool $defer_relay_side_effects = false;
|
||||
|
||||
/**
|
||||
* Set the license plate of the vehicle currently in the lane
|
||||
@@ -24,6 +25,12 @@ class selfserve_lane_command_arguments
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setDeferRelaySideEffects(bool $defer_relay_side_effects): self
|
||||
{
|
||||
$this->defer_relay_side_effects = $defer_relay_side_effects;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setParameters($params): self
|
||||
{
|
||||
if (is_array($params)) {
|
||||
@@ -33,7 +40,13 @@ class selfserve_lane_command_arguments
|
||||
if (array_key_exists('customer_number', $params)) {
|
||||
$this->setCustomerNumber($params['customer_number']);
|
||||
}
|
||||
if (array_key_exists('defer_relay_side_effects', $params)) {
|
||||
$this->setDeferRelaySideEffects(filter_var(
|
||||
$params['defer_relay_side_effects'],
|
||||
FILTER_VALIDATE_BOOLEAN
|
||||
));
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,66 @@ trait selfserve_lane_command_t
|
||||
}
|
||||
}
|
||||
|
||||
protected function openEntrancePortForWashStart(): void
|
||||
{
|
||||
try {
|
||||
$this->open(selfserve_lane_port::ENTRANCE);
|
||||
} catch (\Throwable $e) {
|
||||
if ($this->isAmbiguousGatewayTimeout($e)) {
|
||||
$this->reportWashStartEntranceTimeout($e);
|
||||
return;
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
protected function isAmbiguousGatewayTimeout(\Throwable $e): bool
|
||||
{
|
||||
$current = $e;
|
||||
while ($current !== null) {
|
||||
$message = strtolower(trim($current->getMessage()));
|
||||
if (
|
||||
str_contains($message, 'edge gateway command timed out') ||
|
||||
str_contains($message, 'command timed out') ||
|
||||
str_contains($message, 'timed out') ||
|
||||
str_contains($message, 'timeout')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$current = $current->getPrevious();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function reportWashStartEntranceTimeout(\Throwable $e): void
|
||||
{
|
||||
try {
|
||||
$laneId = isset($this->id) ? (string)$this->id : 'unknown';
|
||||
error_log(
|
||||
'Self-serve START entrance gate dispatch timed out for lane ' .
|
||||
$laneId .
|
||||
'; continuing wash start because the gateway command may already have reached the relay: ' .
|
||||
$e->getMessage()
|
||||
);
|
||||
} catch (\Throwable) {
|
||||
// Diagnostics must not block the user wash start flow.
|
||||
}
|
||||
}
|
||||
|
||||
protected function runRelaySideEffectsForWashStart(selfserve_lane_command_arguments $arguments): void
|
||||
{
|
||||
if ($arguments->defer_relay_side_effects) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure cleaner relay is enabled whenever wash starts.
|
||||
$this->turnOnCleanerRelayForWashStart();
|
||||
// Ensure the machine relay is ON when a wash starts, when it is allowed.
|
||||
$this->setMachineRelayStatusForWashStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable relays after STOP in deterministic order:
|
||||
@@ -293,21 +353,28 @@ trait selfserve_lane_command_t
|
||||
// Validate customer number
|
||||
if (!is_numeric($customer_number) || (int)$customer_number <= 0) throw new \InvalidArgumentException("Invalid customer number: " . $customer_number);
|
||||
if (!(new users_o())->getUserByCustomerNumber((int)$customer_number)->exists()) throw new \InvalidArgumentException("Customer number does not exist: " . $customer_number);
|
||||
$previous_customer_number = $this->getCustomerNumber();
|
||||
$previous_license_plate = $this->getLicensePlate();
|
||||
// Set the customer number and license plate
|
||||
$this->setCustomerNumber($customer_number);
|
||||
$this->setLicensePlate($license_plate);
|
||||
try {
|
||||
// Open the entrance port before marking the lane occupied. Gateway timeouts are
|
||||
// ambiguous because the relay may already have received the pulse.
|
||||
$this->openEntrancePortForWashStart();
|
||||
} catch (\Throwable $e) {
|
||||
$this->setCustomerNumber($previous_customer_number);
|
||||
$this->setLicensePlate($previous_license_plate);
|
||||
$this->setLaneState(selfserve_lane_state::IDLE);
|
||||
throw $e;
|
||||
}
|
||||
// Set the lane status to OCCUPIED when started
|
||||
$this->setLaneStatus(selfserve_lane_status::OCCUPIED);
|
||||
// Set the lane state to IN_WASH
|
||||
$this->setLaneState(selfserve_lane_state::IN_WASH);
|
||||
// Open the entrance port
|
||||
$this->open(selfserve_lane_port::ENTRANCE);
|
||||
// Start the wash timer
|
||||
$this->setWashStartTime(time());
|
||||
// Ensure cleaner relay is enabled whenever wash starts.
|
||||
$this->turnOnCleanerRelayForWashStart();
|
||||
// Ensure the machine relay is ON when a wash starts, when it is allowed.
|
||||
$this->setMachineRelayStatusForWashStart();
|
||||
$this->runRelaySideEffectsForWashStart($arguments);
|
||||
// Log the lane start event
|
||||
$this->logLaneAction(selfserve_lane_log_action::START_WASH);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user