소개
단체톡방에서 매일 일정시간에 날씨 알림을 보내고 싶었어요
진행 방법
항상 Perplexity api를 이용해서 봇을 쓰는 법을 알려주셔서 활용해봤습니다
// 스케줄링 설정
MORNING_HOUR: 22, // 날씨 검색 시간 (24시간 형식)
MORNING_QUERY: "내일 서울 날씨" // 저녁에 자동 검색할 내용// ===== 라인 47-50 =====
var Scheduler = {
lastExecutedDate: "", // 메모리 캐시 (YYYY-MM-DD-HH 형식)
isRunning: false, // Thread 중복 방지 플래그
STATE_FILE: "/storage/emulated/0/msgbot/weatherbot_last_exec.txt",// ===== 라인 53-67 =====
loadLastExecutedDate: function() {
try {
var file = new java.io.File(this.STATE_FILE);
if (!file.exists()) {
return "";
}
var reader = new java.io.BufferedReader(new java.io.FileReader(file));
var dateStr = reader.readLine(); // "2025-11-16-05" 형식
reader.close();
return dateStr || "";
} catch (e) {
Log.e("파일 읽기 오류: " + e.message);
return "";
}
}// ===== 라인 70-94 =====
saveLastExecutedDate: function(dateStr) {
try {
var file = new java.io.File(this.STATE_FILE);
var parent = file.getParentFile();
if (parent && !parent.exists()) {
parent.mkdirs(); // 디렉토리 생성
}
// ⚡ Atomic write 패턴
var tempFile = new java.io.File(this.STATE_FILE + ".tmp");
var writer = new java.io.FileWriter(tempFile);
writer.write(dateStr); // 임시 파일에 쓰기
writer.close();
// 원자적 rename (기존 파일 덮어쓰기)
if (file.exists()) {
file.delete();
}
tempFile.renameTo(file); // 순간적으로 교체
Log.d("✅ 실행 날짜 저장: " + dateStr);
} catch (e) {
Log.e("파일 저장 오류: " + e.message);
}
}// ===== 라인 97-143 =====
checkSchedule: function() {
var now = new Date();
var currentHour = now.getHours();
var currentMinute = now.getMinutes();
// ===== 1. 현재 날짜+시간을 YYYY-MM-DD-HH 형식으로 생성 =====
var year = now.getFullYear();
var month = (now.getMonth() + 1).toString();
var day = now.getDate().toString();
var hour = currentHour.toString();
if (month.length === 1) month = "0" + month;
if (day.length === 1) day = "0" + day;
if (hour.length === 1) hour = "0" + hour;
var currentDateHour = year + "-" + month + "-" + day + "-" + hour;
// 예: "2025-11-16-05"
// ===== 2. 시간 윈도우 체크 (20분 범위) =====
if (currentHour < CONFIG.MORNING_HOUR) return; // 설정 시간 전
if (currentHour > CONFIG.MORNING_HOUR) return; // 설정 시간 지남
if (currentMinute > 20) return; // 20분 이후
// → 5:00 ~ 5:20 사이에만 실행
// ===== 3. 파일 기반 중복 체크 (글로벌 락) =====
var savedDateHour = this.loadLastExecutedDate();
if (savedDateHour === currentDateHour) {
// 이미 이 시간에 실행됨 (다른 Thread 포함)
return;
}
// ===== 4. 메모리 캐시 체크 (추가 보호) =====
if (this.lastExecutedDate === currentDateHour) return;
// ===== 5. 실행 조건 만족! =====
Log.i("🔍 스케줄 체크: " + currentHour + ":" + currentMinute +
" 날짜+시간:" + currentDateHour + " 마지막:" + savedDateHour);
// ===== 6. 즉시 파일 저장 (다른 Thread 차단) =====
this.saveLastExecutedDate(currentDateHour);
this.lastExecutedDate = currentDateHour;
Log.i("⏰ 예약된 날씨 검색 실행 (날짜+시간: " + currentDateHour +
", 설정: " + CONFIG.MORNING_HOUR + "시)");
// ===== 7. 모든 대상 방에서 검색 실행 =====
for (var i = 0; i < CONFIG.TARGET_ROOMS.length; i++) {
var room = CONFIG.TARGET_ROOMS[i];
this.executeScheduledSearch(room, CONFIG.MORNING_QUERY);
}
}// ===== 라인 146-160 =====
executeScheduledSearch: function(room, query) {
Log.i("예약 검색: '" + query + "' in '" + room + "'");
// 가짜 메시지 객체 생성 (스케줄러가 사용자인 척)
var fakeMsg = {
room: room,
content: CONFIG.TRIGGER_PREFIX + " " + query, // "!검색 내일 서울 날씨"
author: {
name: "스케줄러"
}
};
// onMessage 직접 호출
onMessage(fakeMsg);
}// ===== 라인 163-206 =====
start: function() {
// ===== Thread 중복 생성 방지 =====
if (this.isRunning) {
Log.i("⚠️ 스케줄러가 이미 실행 중입니다. 중복 실행 방지.");
return;
}
this.isRunning = true;
Log.i("✅ 스케줄러 Thread 시작");
new java.lang.Thread(function() {
while (true) { // 무한 루프
try {
Scheduler.checkSchedule(); // 스케줄 체크
// 1분마다 체크 (60초 = 60000ms)
java.lang.Thread.sleep(60000);
} catch(e) {
Log.e("❌ 스케줄러 오류: " + e.message);
if (e.stack) {
Log.e("스택: " + e.stack);
}
// InterruptedException 발생 시 Thread 종료
if (e.toString().indexOf("InterruptedException") !== -1) {
Log.d("스케줄러 Thread 인터럽트");
Scheduler.isRunning = false;
break;
}
// 오류 시 5초 대기 후 재시도
try {
java.lang.Thread.sleep(5000);
} catch(se) {
Log.e("재시도 실패, Thread 종료");
Scheduler.isRunning = false;
break;
}
}
}
Log.i("🛑 스케줄러 Thread 종료");
Scheduler.isRunning = false;
}).start();
}// ===== 라인 318-339 =====
if (content === "!스케줄확인") {
var now = new Date();
var year = now.getFullYear();
var month = (now.getMonth() + 1).toString();
var day = now.getDate().toString();
if (month.length === 1) month = "0" + month;
if (day.length === 1) day = "0" + day;
var currentDate = year + "-" + month + "-" + day;
// 파일에서 실제 마지막 실행 날짜 읽기
var savedDate = Scheduler.loadLastExecutedDate();
var statusMsg = "📅 스케줄러 상태\n\n";
statusMsg += "현재 시간: " + now.getHours() + ":" + now.getMinutes() + "\n";
statusMsg += "현재 날짜: " + currentDate + "\n";
statusMsg += "마지막 실행 날짜: " + (savedDate || "없음") + "\n";
statusMsg += "설정 시간: " + CONFIG.MORNING_HOUR + "시\n";
statusMsg += "검색 쿼리: " + CONFIG.MORNING_QUERY;
bot.send(msg.room, statusMsg);
return;매일 22시에 내일 서울 날씨 검색이 되도록 클로드코드에게 코드작성을 해달라고 한 코드입니다
그런데 컴파일을 하면 22시에 되지만 다음 날이 되면 되지가 않아요
비개발자라 보니 왜 안되는지 이유는 모르겠고
이거 이후에 계속 수정을 해달라고 했지만 더 이상하게 꼬이기만하고 결국 실패를 했습니다
결과와 배운 점
수정을 해달라고 하면 안될 것 같고 아예 처음부터 해보는 방법도 좋을 것 같아요
도움 받은 글 (옵션)
예시로 받은 카톡봇