-
Notifications
You must be signed in to change notification settings - Fork 463
Expand file tree
/
Copy pathproduction.js
More file actions
178 lines (146 loc) · 4.83 KB
/
production.js
File metadata and controls
178 lines (146 loc) · 4.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/**
* 生产模式下的服务器入口
* 使用 NODE_ENV=production node production.js 来启动
*/
process.env.NODE_ENV = 'production';
const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');
const path = require('path');
const http = require('http');
const { createWebSocketServer } = require('./websocket');
// 调用 generate-manifest.js 生成 manifest.json
function generateManifest() {
console.log('Generating manifest.json for Docker deployment...');
try {
const generateManifestScript = path.join(
__dirname,
'scripts',
'generate-manifest.js'
);
require(generateManifestScript);
} catch (error) {
console.error('❌ Error calling generate-manifest.js:', error);
throw error;
}
}
// 生成manifest
generateManifest();
const hostname = process.env.HOSTNAME || '0.0.0.0';
const port = process.env.PORT || 3000;
// 在生产模式下初始化 Next.js
const app = next({
dev: false,
hostname,
port
});
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = createServer(async (req, res) => {
try {
// 检查是否是WebSocket升级请求,如果是则跳过Next.js处理
const upgrade = req.headers.upgrade;
if (upgrade && upgrade.toLowerCase() === 'websocket') {
// 不处理WebSocket升级请求,让upgrade事件处理器处理
return;
}
// 使用Next.js处理所有非WebSocket请求
const parsedUrl = parse(req.url, true);
await handle(req, res, parsedUrl);
} catch (err) {
console.error('处理请求时出错:', req.url, err);
res.statusCode = 500;
res.end('内部服务器错误');
}
});
// 初始化 WebSocket 服务器
const wss = createWebSocketServer();
// 将 WebSocket 服务器实例存储到全局对象中,供 API 路由使用
global.wss = wss;
// 使用WeakSet来跟踪已处理的socket,避免重复处理
const handledSockets = new WeakSet();
// 处理 WebSocket 升级请求
server.on('upgrade', (request, socket, head) => {
// 如果socket已经被处理过,直接返回
if (handledSockets.has(socket)) {
return;
}
const pathname = parse(request.url).pathname;
if (pathname === '/ws') {
console.log('处理 WebSocket 升级请求:', pathname);
// 标记socket已被处理
handledSockets.add(socket);
// 处理WebSocket连接
try {
wss.handleUpgrade(request, socket, head, (ws) => {
wss.emit('connection', ws, request);
});
} catch (error) {
console.error('WebSocket升级错误:', error);
socket.destroy();
}
} else {
console.log('未知的升级请求路径:', pathname);
// 不销毁socket,让它自然关闭
}
});
// 启动服务器
server.listen(port, (err) => {
if (err) throw err;
console.log(`> 服务已启动 (生产模式): http://${hostname}:${port}`);
console.log(`> WebSocket 服务已启动: ws://${hostname}:${port}/ws`);
// 设置服务器启动后的任务
setupServerTasks();
});
});
// 设置服务器启动后的任务
function setupServerTasks() {
// 每 1 秒轮询一次,直到请求成功
const TARGET_URL = `http://${process.env.HOSTNAME || 'localhost'}:${process.env.PORT || 3000}/login`;
const intervalId = setInterval(() => {
console.log(`Fetching ${TARGET_URL} ...`);
const req = http.get(TARGET_URL, (res) => {
// 当返回 2xx 状态码时认为成功,然后停止轮询
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
console.log('Server is up, stop polling.');
clearInterval(intervalId);
setTimeout(() => {
// 服务器启动后,立即执行一次 cron 任务
executeCronJob();
}, 3000);
// 然后设置每小时执行一次 cron 任务
setInterval(() => {
executeCronJob();
}, 60 * 60 * 1000); // 每小时执行一次
}
});
req.setTimeout(2000, () => {
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();
});
}