mirror of
https://github.com/MoonTechLab/LunaTV.git
synced 2026-02-21 00:44:41 +08:00
feat: refine cron job
This commit is contained in:
@@ -38,7 +38,6 @@
|
||||
"next": "^14.2.23",
|
||||
"next-pwa": "^5.6.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"node-cron": "^4.2.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-icons": "^5.4.0",
|
||||
|
||||
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@@ -62,9 +62,6 @@ importers:
|
||||
next-themes:
|
||||
specifier: ^0.4.6
|
||||
version: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
node-cron:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
react:
|
||||
specifier: ^18.2.0
|
||||
version: 18.3.1
|
||||
@@ -4774,10 +4771,6 @@ packages:
|
||||
no-case@3.0.4:
|
||||
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
|
||||
|
||||
node-cron@4.2.0:
|
||||
resolution: {integrity: sha512-nOdP7uH7u55w7ybQq9fusXtsResok+ErzvOBydJUPBBaQ9W+EfBaBWFPgJ8sOB7FWQednDvVBJtgP5xA0bME7Q==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
|
||||
node-fetch@2.6.7:
|
||||
resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
|
||||
engines: {node: 4.x || >=6.0.0}
|
||||
@@ -11689,8 +11682,6 @@ snapshots:
|
||||
lower-case: 2.0.2
|
||||
tslib: 2.8.1
|
||||
|
||||
node-cron@4.2.0: {}
|
||||
|
||||
node-fetch@2.6.7:
|
||||
dependencies:
|
||||
whatwg-url: 5.0.0
|
||||
|
||||
@@ -1,13 +1,45 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
import { db } from '@/lib/db';
|
||||
import { fetchVideoDetail } from '@/lib/fetchVideoDetail';
|
||||
import { SearchResult } from '@/lib/types';
|
||||
|
||||
const STORAGE_TYPE = process.env.NEXT_PUBLIC_STORAGE_TYPE ?? 'localstorage';
|
||||
export const runtime = 'edge';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
console.log(request.url);
|
||||
try {
|
||||
console.log('Cron job triggered:', new Date().toISOString());
|
||||
|
||||
refreshRecordAndFavorites();
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: 'Cron job executed successfully',
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Cron job failed:', error);
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
success: false,
|
||||
message: 'Cron job failed',
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshRecordAndFavorites() {
|
||||
if (STORAGE_TYPE === 'localstorage') {
|
||||
if (
|
||||
process.env.NEXT_PUBLIC_STORAGE_TYPE ||
|
||||
'localstorage' === 'localstorage'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -155,5 +187,3 @@ async function refreshRecordAndFavorites() {
|
||||
console.error('刷新播放记录/收藏任务启动失败', err);
|
||||
}
|
||||
}
|
||||
|
||||
export default refreshRecordAndFavorites;
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { Metadata, Viewport } from 'next';
|
||||
import { Inter } from 'next/font/google';
|
||||
import '../lib/cron';
|
||||
|
||||
import './globals.css';
|
||||
import 'sweetalert2/dist/sweetalert2.min.css';
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import cron from 'node-cron';
|
||||
|
||||
import refreshRecordAndFavorites from '@/lib/refreshRecordAndFavorites';
|
||||
|
||||
/*
|
||||
* 初始化定时任务:每个小时的 02 分执行一次。
|
||||
* 若需要添加更多任务,可在此文件中继续编写。
|
||||
*/
|
||||
|
||||
declare global {
|
||||
// 避免在开发热重载或多次导入时重复初始化
|
||||
// eslint-disable-next-line no-var
|
||||
var __moonTVCronInitialized: boolean | undefined;
|
||||
}
|
||||
|
||||
if (!global.__moonTVCronInitialized) {
|
||||
cron.schedule(
|
||||
'2 * * * *',
|
||||
async () => {
|
||||
refreshRecordAndFavorites();
|
||||
},
|
||||
{
|
||||
timezone: 'Asia/Shanghai',
|
||||
}
|
||||
);
|
||||
|
||||
global.__moonTVCronInitialized = true;
|
||||
}
|
||||
|
||||
export {}; // 仅用于确保这是一个模块
|
||||
@@ -1,12 +1,8 @@
|
||||
/* eslint-disable no-console, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
|
||||
|
||||
import { getRequestContext } from '@cloudflare/next-on-pages';
|
||||
|
||||
import { AdminConfig } from './admin.types';
|
||||
import { Favorite, IStorage, PlayRecord } from './types';
|
||||
|
||||
export const runtime = 'edge';
|
||||
|
||||
// 搜索历史最大条数
|
||||
const SEARCH_HISTORY_LIMIT = 20;
|
||||
|
||||
@@ -120,17 +116,6 @@ const INIT_SQL = `
|
||||
|
||||
// 获取全局D1数据库实例
|
||||
function getD1Database(): D1Database {
|
||||
try {
|
||||
// 在 Cloudflare Pages 环境中,通过 getRequestContext 访问 D1 数据库
|
||||
const { env } = getRequestContext();
|
||||
if (env && (env as any).DB) {
|
||||
return (env as any).DB as D1Database;
|
||||
}
|
||||
} catch (error) {
|
||||
// 如果 getRequestContext 失败,继续尝试其他方式
|
||||
console.warn('Failed to get request context:', error);
|
||||
}
|
||||
|
||||
// 在 next-on-pages 环境中,D1 数据库可能通过 process.env 暴露
|
||||
if (typeof process !== 'undefined' && (process.env as any).DB) {
|
||||
return (process.env as any).DB as D1Database;
|
||||
@@ -145,10 +130,6 @@ export class D1Storage implements IStorage {
|
||||
private db: D1Database | null = null;
|
||||
private initialized = false;
|
||||
|
||||
constructor() {
|
||||
// 不在构造函数中初始化数据库,延迟到实际使用时
|
||||
}
|
||||
|
||||
private async getDatabase(): Promise<D1Database> {
|
||||
if (!this.db) {
|
||||
this.db = getD1Database();
|
||||
|
||||
42
start.js
42
start.js
@@ -19,6 +19,14 @@ const intervalId = setInterval(() => {
|
||||
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
||||
console.log('Server is up, stop polling.');
|
||||
clearInterval(intervalId);
|
||||
|
||||
// 服务器启动后,立即执行一次 cron 任务
|
||||
executeCronJob();
|
||||
|
||||
// 然后设置每小时执行一次 cron 任务
|
||||
setInterval(() => {
|
||||
executeCronJob();
|
||||
}, 60 * 60 * 1000); // 每小时执行一次
|
||||
}
|
||||
});
|
||||
|
||||
@@ -26,3 +34,37 @@ const intervalId = setInterval(() => {
|
||||
req.destroy();
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
// 执行 cron 任务的函数
|
||||
function executeCronJob() {
|
||||
const cronUrl = `http://${process.env.HOSTNAME || 'localhost'}:${
|
||||
process.env.PORT || 3000
|
||||
}/api/cron`;
|
||||
|
||||
console.log(`Executing cron job: ${cronUrl}`);
|
||||
|
||||
const req = http.get(cronUrl, (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
||||
console.log('Cron job executed successfully:', data);
|
||||
} else {
|
||||
console.error('Cron job failed:', res.statusCode, data);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (err) => {
|
||||
console.error('Error executing cron job:', err);
|
||||
});
|
||||
|
||||
req.setTimeout(30000, () => {
|
||||
console.error('Cron job timeout');
|
||||
req.destroy();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user