worker service 매물 등록 및 redis 다운시 처리
This commit is contained in:
@@ -4,6 +4,40 @@
|
||||
* - 프레임워크를 로드하지 않아 매우 빠르고 안전함
|
||||
* - 받은 데이터를 Redis 큐에 넣고 즉시 응답 테스트
|
||||
*/
|
||||
|
||||
// .env 파일 로드 함수 (프레임워크 미사용 환경)
|
||||
function loadEnvFile($filePath) {
|
||||
if (!file_exists($filePath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
foreach ($lines as $line) {
|
||||
// 주석 제거
|
||||
if (strpos(trim($line), '#') === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// KEY = VALUE 파싱
|
||||
if (strpos($line, '=') !== false) {
|
||||
list($key, $value) = explode('=', $line, 2);
|
||||
$key = trim($key);
|
||||
$value = trim($value);
|
||||
|
||||
// 따옴표 제거
|
||||
$value = trim($value, '"\'');
|
||||
|
||||
// 환경변수 설정 (이미 있으면 덮어쓰지 않음)
|
||||
if (!getenv($key)) {
|
||||
putenv("$key=$value");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// .env 파일 로드 (한 단계 상위 디렉토리)
|
||||
loadEnvFile(__DIR__ . '/../.env');
|
||||
|
||||
/**
|
||||
* 날짜별 로그 기록 함수
|
||||
* @param string $message 로그 내용
|
||||
@@ -76,67 +110,111 @@ writeLog("REQUEST_INFO | " . json_encode($requestInfo, JSON_UNESCAPED_UNICODE |
|
||||
// ================================================================
|
||||
|
||||
// 2. 보안 키 체크 (URL 파라미터 key=값)
|
||||
$configKey = "7EE868F4B36D36B3D86736828F4729EAC4992083"; // 실제 사용할 키값으로 변경하세요
|
||||
$configKey = getenv('API_RECEIVER_KEY') ?: "7EE868F4B36D36B3D86736828F4729EAC4992083";
|
||||
$receivedKey = $_GET['key'] ?? '';
|
||||
$logDir = __DIR__ . '/logs/';
|
||||
|
||||
if ($receivedKey !== $configKey) {
|
||||
writeLog("SECURITY_FAIL | Invalid key: $receivedKey", 'WARNING');
|
||||
http_response_code(403);
|
||||
echo apiResponse([
|
||||
'code' => '-1',
|
||||
'code' => 'E403',
|
||||
'message' => 'Unregistered key'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
// 3. 데이터 수신 (POST JSON 또는 GET 파라미터)
|
||||
// 3. 데이터 수신 및 검증 (POST JSON)
|
||||
if (empty($rawData)) {
|
||||
throw new Exception("No data received");
|
||||
}
|
||||
|
||||
$data = json_decode($rawData, true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
throw new Exception("Invalid JSON format: " . json_last_error_msg());
|
||||
}
|
||||
|
||||
if (empty($data)) {
|
||||
throw new Exception("Empty data received");
|
||||
}
|
||||
// 4. Redis 연결
|
||||
$redis = new Redis();
|
||||
// Docker 서비스 이름인 'redis' 사용
|
||||
$redisHost = getenv('REDIS_HOST') ?: 'infra-redis'; // ✅ 가능
|
||||
$redisPort = getenv('REDIS_PORT') ?: 6379;
|
||||
$success = $redis->connect($redisHost, $redisPort);
|
||||
|
||||
if (!$success) {
|
||||
throw new Exception("Could not connect to Redis");
|
||||
}
|
||||
|
||||
$redis->select(9); // 10번 DB 사용
|
||||
|
||||
// 5. 큐에 넣을 데이터 포맷팅
|
||||
// 4. 페이로드 준비
|
||||
$payload = [
|
||||
'request_data' => $data,
|
||||
'received_at' => date('Y-m-d H:i:s'),
|
||||
'client_ip' => $_SERVER['REMOTE_ADDR']
|
||||
'client_ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
|
||||
];
|
||||
|
||||
// 'naver:raw_queue'라는 이름의 리스트에 저장
|
||||
$redis->lPush('naver:raw_queue', json_encode($payload));
|
||||
// 5. Redis 연결 시도 및 폴백 처리
|
||||
$redisSuccess = false;
|
||||
$redis = new Redis();
|
||||
|
||||
try {
|
||||
// .env 환경변수에서 Redis 설정 읽기
|
||||
$redisHost = getenv('REDIS_HOST') ?: '127.0.0.1';
|
||||
$redisPort = getenv('REDIS_PORT') ?: 6379;
|
||||
$redisDatabase = getenv('REDIS_DATABASE') ?: 9;
|
||||
|
||||
$success = $redis->connect($redisHost, (int)$redisPort, 2.5); // 2.5초 타임아웃
|
||||
|
||||
if (!$success) {
|
||||
throw new Exception("Could not connect to Redis at {$redisHost}:{$redisPort}");
|
||||
}
|
||||
|
||||
// 6. 네이버측에 성공 응답 (202 Accepted)
|
||||
// 처리가 완료된 것은 아니지만, 접수는 완료되었음을 의미
|
||||
$redis->select((int)$redisDatabase);
|
||||
|
||||
// 'naver:raw_queue'라는 이름의 리스트에 저장
|
||||
$pushResult = $redis->lPush('naver:raw_queue', json_encode($payload));
|
||||
|
||||
if (!$pushResult) {
|
||||
throw new Exception("Failed to push data to Redis queue");
|
||||
}
|
||||
|
||||
$redisSuccess = true;
|
||||
writeLog("SUCCESS | Redis queue length: {$pushResult} | IP: " . ($payload['client_ip'] ?? 'unknown'), 'INFO');
|
||||
|
||||
} catch (Exception $redisError) {
|
||||
// Redis 실패 시 파일 폴백
|
||||
writeLog("REDIS_FAIL | " . $redisError->getMessage() . " | Using file fallback", 'WARNING');
|
||||
|
||||
// 폴백 디렉토리 생성 및 권한 설정
|
||||
$fallbackDir = __DIR__ . '/fallback_queue';
|
||||
if (!is_dir($fallbackDir)) {
|
||||
if (!mkdir($fallbackDir, 0777, true) && !is_dir($fallbackDir)) {
|
||||
throw new Exception("Failed to create fallback directory");
|
||||
}
|
||||
chmod($fallbackDir, 0777);
|
||||
}
|
||||
|
||||
// 파일로 저장 (타임스탬프 + 유니크ID)
|
||||
$filename = $fallbackDir . '/' . date('YmdHis') . '_' . uniqid() . '.json';
|
||||
$writeResult = file_put_contents($filename, json_encode($payload), LOCK_EX);
|
||||
|
||||
if ($writeResult === false) {
|
||||
throw new Exception("Failed to write fallback file");
|
||||
}
|
||||
|
||||
chmod($filename, 0666);
|
||||
writeLog("FALLBACK_SUCCESS | File: " . basename($filename) . " | IP: " . ($payload['client_ip'] ?? 'unknown'), 'INFO');
|
||||
}
|
||||
|
||||
// 6. 성공 응답 (Redis 또는 Fallback 성공)
|
||||
http_response_code(200);
|
||||
echo apiResponse([
|
||||
'code' => 'success',
|
||||
'message' => ''
|
||||
'code' => 'success',
|
||||
'message' => ''
|
||||
]);
|
||||
|
||||
|
||||
} catch (Exception $e) {
|
||||
// 7. 장애 발생 시 로그 기록 (시스템 로그)
|
||||
writeLog( 'Exception :' . apiResponse($data) , 'ERROR');
|
||||
// 7. 완전 장애 발생 시 (Redis도 실패, File도 실패)
|
||||
writeLog('CRITICAL_ERROR: ' . $e->getMessage() . ' | Data: ' . substr($rawData, 0, 200), 'ERROR');
|
||||
|
||||
http_response_code(500);
|
||||
|
||||
echo apiResponse([
|
||||
'code' => '-1',
|
||||
'message' => $e->getMessage()
|
||||
'code' => 'E999',
|
||||
'message' => 'Internal server error'
|
||||
]);
|
||||
}
|
||||
Reference in New Issue
Block a user