phase 7
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\ApiLog;
|
||||
use App\Models\JobSource;
|
||||
use Illuminate\Http\Client\PendingRequest;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ApiClientService
|
||||
{
|
||||
/**
|
||||
* Make an API request with logging and retry logic
|
||||
*/
|
||||
public function makeRequest(
|
||||
JobSource $source,
|
||||
string $endpoint,
|
||||
string $method = 'GET',
|
||||
array $params = [],
|
||||
int $maxRetries = 3
|
||||
): array {
|
||||
$startTime = microtime(true);
|
||||
$attempt = 0;
|
||||
$lastException = null;
|
||||
|
||||
while ($attempt < $maxRetries) {
|
||||
$attempt++;
|
||||
|
||||
try {
|
||||
$response = $this->executeRequest($method, $endpoint, $params);
|
||||
$responseTime = (int)((microtime(true) - $startTime) * 1000);
|
||||
|
||||
// Log successful request
|
||||
$this->logApiRequest($source, $endpoint, $method, $params, $response, $responseTime, true);
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'data' => $response->json(),
|
||||
'status_code' => $response->status(),
|
||||
'response_time' => $responseTime,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
$lastException = $e;
|
||||
|
||||
// Log failed attempt
|
||||
Log::warning("API request failed (attempt {$attempt}/{$maxRetries})", [
|
||||
'source' => $source->name,
|
||||
'endpoint' => $endpoint,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
if ($attempt < $maxRetries) {
|
||||
// Exponential backoff: wait 2^attempt seconds
|
||||
sleep(pow(2, $attempt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$responseTime = (int)((microtime(true) - $startTime) * 1000);
|
||||
|
||||
// Log final failure
|
||||
$this->logApiRequest(
|
||||
$source,
|
||||
$endpoint,
|
||||
$method,
|
||||
$params,
|
||||
null,
|
||||
$responseTime,
|
||||
false,
|
||||
$lastException->getMessage() ?? 'Unknown error'
|
||||
);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'error' => $lastException->getMessage() ?? 'Unknown error',
|
||||
'response_time' => $responseTime,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the HTTP request
|
||||
*/
|
||||
private function executeRequest(string $method, string $endpoint, array $params): \Illuminate\Http\Client\Response
|
||||
{
|
||||
$http = Http::timeout(30)
|
||||
->retry(1, 100)
|
||||
->withHeaders([
|
||||
'User-Agent' => 'JobifyGarden/1.0',
|
||||
'Accept' => 'application/json',
|
||||
]);
|
||||
|
||||
return match (strtoupper($method)) {
|
||||
'GET' => $http->get($endpoint, $params),
|
||||
'POST' => $http->post($endpoint, $params),
|
||||
'PUT' => $http->put($endpoint, $params),
|
||||
'DELETE' => $http->delete($endpoint, $params),
|
||||
default => throw new \InvalidArgumentException("Unsupported HTTP method: {$method}"),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Log API request to database
|
||||
*/
|
||||
private function logApiRequest(
|
||||
JobSource $source,
|
||||
string $endpoint,
|
||||
string $method,
|
||||
array $params,
|
||||
$response,
|
||||
int $responseTime,
|
||||
bool $success,
|
||||
?string $errorMessage = null
|
||||
): void {
|
||||
try {
|
||||
ApiLog::create([
|
||||
'job_source_id' => $source->id,
|
||||
'endpoint' => $endpoint,
|
||||
'method' => $method,
|
||||
'status_code' => $response?->status(),
|
||||
'response_time_ms' => $responseTime,
|
||||
'success' => $success,
|
||||
'error_message' => $errorMessage,
|
||||
'request_params' => !empty($params) ? $params : null,
|
||||
'response_data' => $success && $response ? [
|
||||
'status' => $response->status(),
|
||||
'size' => strlen($response->body()),
|
||||
] : null,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Failed to log API request', [
|
||||
'error' => $e->getMessage(),
|
||||
'endpoint' => $endpoint,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if source is rate limited
|
||||
*/
|
||||
public function isRateLimited(JobSource $source): bool
|
||||
{
|
||||
if (!$source->rate_limit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check requests in the last hour
|
||||
$recentRequests = ApiLog::where('job_source_id', $source->id)
|
||||
->where('created_at', '>=', now()->subHour())
|
||||
->count();
|
||||
|
||||
return $recentRequests >= $source->rate_limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rate limit info for a source
|
||||
*/
|
||||
public function getRateLimitInfo(JobSource $source): array
|
||||
{
|
||||
$recentRequests = ApiLog::where('job_source_id', $source->id)
|
||||
->where('created_at', '>=', now()->subHour())
|
||||
->count();
|
||||
|
||||
return [
|
||||
'limit' => $source->rate_limit,
|
||||
'used' => $recentRequests,
|
||||
'remaining' => max(0, $source->rate_limit - $recentRequests),
|
||||
'reset_at' => now()->addHour()->startOfHour(),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user