class WeatherEmailService
{
private $maxRetries = 3;
private $debugInfo = [];
public function sendWeatherUpdate(string $location, string $email)
{
try {
$response = $this->executeWithRetry(function () use ($location, $email) {
return Prism::text()
->withSystemPrompt("Get weather and send via email. Handle errors gracefully.")
->withPrompt("Send {$location} weather to {$email}")
->withTools([$this->weatherTool, $this->emailTool])
->withMaxSteps(5)
->generate();
});
$this->validateResponse($response);
return $this->processResponse($response);
} catch (WeatherToolException $e) {
Log::error('Weather API Error', [
'location' => $location,
'error' => $e->getMessage(),
'debug_info' => $this->debugInfo
]);
// Fallback to cached weather data
return $this->sendCachedWeather($location, $email);
} catch (EmailToolException $e) {
Log::error('Email Send Error', [
'email' => $email,
'error' => $e->getMessage(),
'debug_info' => $this->debugInfo
]);
// Queue for retry
WeatherEmailRetryJob::dispatch($location, $email)
->delay(now()->addMinutes(5));
throw new ServiceException(
"Unable to send email. Queued for retry.",
previous: $e
);
}
}
private function executeWithRetry(callable $operation)
{
$attempt = 1;
$lastException = null;
while ($attempt <= $this->maxRetries) {
try {
return $operation();
} catch (Exception $e) {
$lastException = $e;
Log::warning("Attempt {$attempt} failed", [
'error' => $e->getMessage(),
'debug_info' => $this->debugInfo
]);
if ($attempt < $this->maxRetries) {
sleep(pow(2, $attempt)); // Exponential backoff
}
$attempt++;
}
}
throw new ServiceException(
"Operation failed after {$this->maxRetries} attempts",
previous: $lastException
);
}
private function validateResponse($response)
{
if (empty($response->steps)) {
throw new ServiceException("No steps in response");
}
// Check if we got weather data
$hasWeatherData = collect($response->steps)
->flatMap->toolResults
->contains(fn($result) =>
$result->toolName === 'weather' && !empty($result->result)
);
if (!$hasWeatherData) {
throw new ServiceException("No weather data in response");
}
}
}