receiver.php 파일 생성
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -141,5 +141,6 @@ _modules/*
|
||||
/phpunit*.xml
|
||||
|
||||
.history/
|
||||
/storage/
|
||||
|
||||
.README
|
||||
77
api_receiver.php
Normal file
77
api_receiver.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* [A 작업] 네이버 검증 요청 실시간 수신 리시버
|
||||
* - 프레임워크를 로드하지 않아 매우 빠르고 안전함
|
||||
* - 받은 데이터를 Redis 큐에 넣고 즉시 응답
|
||||
*/
|
||||
|
||||
// 1. 응답 헤더 설정 (JSON)
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
// 2. 보안 키 체크 (URL 파라미터 key=값)
|
||||
$configKey = "YOUR_SECRET_KEY_HERE"; // 실제 사용할 키값으로 변경하세요
|
||||
$receivedKey = $_GET['key'] ?? '';
|
||||
|
||||
if ($receivedKey !== $configKey) {
|
||||
http_response_code(403);
|
||||
echo json_encode([
|
||||
'resultCode' => 'E003',
|
||||
'resultMessage' => 'Invalid API Key'
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
// 3. 데이터 수신 (POST JSON 또는 GET 파라미터)
|
||||
$rawData = file_get_contents('php://input');
|
||||
$data = json_decode($rawData, true);
|
||||
|
||||
// JSON 데이터가 비어있다면 GET 파라미터 사용 (테스트용)
|
||||
if (empty($data)) {
|
||||
$data = $_GET;
|
||||
}
|
||||
|
||||
if (empty($data)) {
|
||||
throw new Exception("Empty data received");
|
||||
}
|
||||
|
||||
// 4. Redis 연결
|
||||
$redis = new Redis();
|
||||
// Docker 서비스 이름인 'redis' 사용
|
||||
$success = $redis->connect('redis', 6379);
|
||||
|
||||
if (!$success) {
|
||||
throw new Exception("Could not connect to Redis");
|
||||
}
|
||||
|
||||
$redis->select(10); // 10번 DB 사용
|
||||
|
||||
// 5. 큐에 넣을 데이터 포맷팅
|
||||
$payload = [
|
||||
'request_data' => $data,
|
||||
'received_at' => date('Y-m-d H:i:s'),
|
||||
'client_ip' => $_SERVER['REMOTE_ADDR']
|
||||
];
|
||||
|
||||
// 'naver:raw_queue'라는 이름의 리스트에 저장
|
||||
$redis->lPush('naver:raw_queue', json_encode($payload));
|
||||
|
||||
// 6. 네이버측에 성공 응답 (202 Accepted)
|
||||
// 처리가 완료된 것은 아니지만, 접수는 완료되었음을 의미
|
||||
http_response_code(202);
|
||||
echo json_encode([
|
||||
'resultCode' => 'S000',
|
||||
'resultMessage' => 'Request accepted and queued',
|
||||
'articleNumber' => $data['articleNumber'] ?? 'N/A'
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
// 7. 장애 발생 시 로그 기록 (시스템 로그)
|
||||
error_log("[API_RECEIVER_ERROR] " . $e->getMessage());
|
||||
|
||||
http_response_code(500);
|
||||
echo json_encode([
|
||||
'resultCode' => 'E999',
|
||||
'resultMessage' => 'Internal System Error: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
100
worker.php
100
worker.php
@@ -1,89 +1,35 @@
|
||||
<?php
|
||||
// worker.php
|
||||
set_time_limit(0);
|
||||
$redisHost = getenv('REDIS_HOST') ?: 'redis';
|
||||
$redisPort = getenv('REDIS_PORT') ?: 6379;
|
||||
|
||||
// --- 설정값 ---
|
||||
$stream = 'vrfc_requests';
|
||||
$group = 'vrfc_group';
|
||||
$consumer = 'php_worker_' . bin2hex(random_bytes(3));
|
||||
$batchSize = 500;
|
||||
// 저장할 기본 경로 (필수 환경 변수 추가 필요)
|
||||
$storagePath = getenv('STORAGE_PATH') ?: '/var/www/html/storage/requests';
|
||||
// ---------------
|
||||
$storagePath = getenv('STORAGE_PATH') ?: '/var/www/html/storage/requests';
|
||||
|
||||
$redis = new Redis();
|
||||
$redis->connect($redisHost, $redisPort);
|
||||
|
||||
// 그룹 생성 (이미 있으면 예외 발생하므로 무시)
|
||||
try {
|
||||
$redis->xGroup('CREATE', $stream, $group, '$');
|
||||
} catch (Exception $e) {}
|
||||
|
||||
// 저장 경로가 없으면 생성 (권한 문제 주의)
|
||||
if (!is_dir($storagePath)) {
|
||||
mkdir($storagePath, 0777, true);
|
||||
$redis->connect($redisHost, 6379);
|
||||
$redis->select(10);
|
||||
echo "[*] Connected to Redis. Waiting for data...\n";
|
||||
} catch (Exception $e) {
|
||||
die("Redis Connection Failed: " . $e->getMessage());
|
||||
}
|
||||
|
||||
|
||||
while (true) {
|
||||
// 1. Stream에서 메시지 읽기
|
||||
$res = $redis->xReadGroup($group, $consumer, [$stream => '>'], $batchSize, 5000);
|
||||
if (!$res) {
|
||||
continue;
|
||||
}
|
||||
// 1. 입구 리스트에서 데이터 꺼내기
|
||||
$item = $redis->brPop(['naver:queue'], 5);
|
||||
if (!$item) continue;
|
||||
|
||||
$jsonStr = $item[1];
|
||||
$data = json_decode($jsonStr, true);
|
||||
|
||||
$entries = $res[$stream];
|
||||
$ids = [];
|
||||
$processedCount = 0;
|
||||
|
||||
foreach ($entries as $id => $fields) {
|
||||
$ids[] = $id;
|
||||
$articleNumbr = $fields['articleNumbr'] ?? '';
|
||||
// 2. 파일 저장
|
||||
$fileName = sprintf('%s_%s.json', $data['articleNumber'], $data['requestDatetime']);
|
||||
$filePath = $storagePath . '/' . $fileName;
|
||||
|
||||
if (file_put_contents($filePath, $jsonStr) !== false) {
|
||||
echo "✅ [SUCCESS] File Saved: $fileName\n";
|
||||
|
||||
if (empty($articleNumbr)) {
|
||||
// 매물 번호가 없으면 실패 스트림으로 이동 후 다음 루프로
|
||||
$fields['fail_reason'] = 'Missing articleNumbr';
|
||||
$redis->xAdd('vrfc_failures', '*', $fields);
|
||||
$redis->xAck($stream, $group, $id);
|
||||
$redis->xDel($stream, $id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2. 파일 저장 로직 실행
|
||||
|
||||
// 파일 이름: 매물번호_요청시간.json
|
||||
$fileName = sprintf('%s_%s.json', $articleNumbr, $fields['requestDatetime']);
|
||||
$filePath = $storagePath . '/' . $fileName;
|
||||
|
||||
// JSON 데이터 (stream fields를 그대로 사용)
|
||||
$jsonData = json_encode($fields, JSON_PRETTY_PRINT);
|
||||
|
||||
try {
|
||||
// 파일에 JSON 데이터 쓰기
|
||||
$result = file_put_contents($filePath, $jsonData);
|
||||
|
||||
if ($result === false) {
|
||||
throw new Exception("File write failed for: {$filePath}");
|
||||
}
|
||||
|
||||
error_log("SUCCESS: Saved request for {$articleNumbr} to {$fileName}");
|
||||
$processedCount++;
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("File save error: " . $e->getMessage());
|
||||
|
||||
// 3. 파일 저장 실패 시 실패 스트림으로 이동 (DLQ)111
|
||||
$fields['fail_reason'] = $e->getMessage();
|
||||
$redis->xAdd('vrfc_failures', '*', $fields);
|
||||
|
||||
// 잠깐 대기
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
// 4. 성공 및 실패 처리 후 ACK 및 삭제
|
||||
$redis->xAck($stream, $group, $id);
|
||||
$redis->xDel($stream, $id);
|
||||
// 3. 파일 저장 성공 시에만 전송 큐로 넘김 (중요!)
|
||||
$redis->lPush('naver:worker_queue', $jsonStr);
|
||||
} else {
|
||||
echo "❌ [ERROR] Failed to save file: $fileName\n";
|
||||
// 실패 시 다시 큐에 넣거나 로그 처리
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user