nodejs定時任務一直是個讓人頭疼的問題,我在作以前就已經看到過不少人發問題問到pm2部署項目之後,多線程的問題下,
如何關閉定時任務,
或者任務被多個線程同時執行
這類問題。前端
第一章手拉手開發nodejs電影cms系統①:內容規劃,導航分類,視頻數據,用戶,留言
第二章手拉手開發nodejs電影cms系統②:定時任務,視頻源數據,初始化數據
第三章手拉手開發nodejs電影cms系統③:寶塔面板懶人部署node
pm2部署沒法關閉任務是由於,用戶(管理員)開啓定時任務的時候,可能被pm2分發到了B線程(假設電腦6核心12線程),你:我電腦就雙核哪來的六核心?mongodb
很差意思,個人12線程。數據庫
扯遠了,扯回來。
當用戶(管理員)想關閉的時候pm2可能把任務分發到了G線程上了,可是G線程上並無執行這個任務,就會報錯。npm
那是由於這個定時任務是項目部署開啓服務的時候就設置好了,到了時間,pm2複製多份任務執行(一毛同樣),固然就會重複跑任務。json
試想一下,若是咱們項目用pm2部署,複製了12份node項目。可是咱們可使用別的進程守護工具,例如forever(單份,單線程)守護定時任務。
說人話:就是分兩個項目部署,定時任務使用一個單線程守護工具,守護。這樣,定時任務到時間之後就是單線程跑了,不會多線程同時調用。隨之而來的一個問題,怎麼通信??pm2那邊的服務怎麼通知forever這邊守護的的進程開啓關閉任務。(http服務啊)segmentfault
假設pm2守護的項目監聽的是8888端口,咱們forever這邊的js開啓的http服務能夠監聽9999。二者之間通信就發post請求。(由於本機的緣由。因此很快,秒收到)這樣,通信的問題解決,就能夠隨時動態的建立/刪除 定時任務了。也不會出現多線程同時執行的問題。session
上一章說了,視頻數據錄入格式。播放源如何錄入,長啥樣?
和留言關聯視頻表,關聯用戶表同樣。視頻源的數據也須要單獨出來,由於若是不單獨出來,咱們只是查詢一下電影列表,不須要展現播放源列表的時候,沒有必要無故帶出來那麼多的數據
多線程
一樣使用mongodb管道聯表操做就能夠很容易關聯出源的數據。async
可能剛入坑nodejs的cxk沒懂,簡稱就是項目初始化默認就必須有的數據,好比博客總得有個默認的後臺系統的root用戶吧,默認的頂級分類,一些默認的配置,從哪來??確定不會天上掉下來。
nodejs pakcage。json的script字段用於定義一些命令。前端的確定知道,npm run dev,npm run build這些你確定經常使用
你徹底能夠再script定義你的初始化數據命令。好比我
"scripts": { "build": "node ./build/initDataBase.js", "restore": "mongorestore -d movie ./backup/movie", "backup": "mongodump -d movie -o ./backup/movie" }
build用於鏈接數據庫,刪除原有的數據庫,建立全新的數據庫,建立字段索引,並向數據庫中插入默認的數據,好比電影cms系統的默認管理員信息。初始化的數據
const mongodb = require('mongodb'), MongoClient = mongodb.MongoClient, config = require('../utils/config.js'), dbConfig = config.project; let connectURL = 'mongodb://127.0.0.1:27017'; let client = MongoClient.connect(connectURL, { useNewUrlParser: true, useUnifiedTopology: true }); client.then(async (db) => { let DB = db.db(dbConfig.dbName); await new Promise(async (resolve, reject) => { console.log('正在清除原始數據表'); await DB.dropCollection('session1').catch(err => {}); await DB.dropCollection('session2').catch(err => {}); await DB.dropCollection('config').catch(err => {}); await DB.dropCollection('logs').catch(err => {}); await DB.dropCollection('message').catch(err => {}); await DB.dropCollection('other').catch(err => {}); await DB.dropCollection('user').catch(err => {}); await DB.dropCollection('video_info').catch(err => {}); await DB.dropCollection('video_list').catch(err => {}); resolve() }) .then(() => { console.log('原始數據表清除完成'); }) .catch(err => { console.log('+++', err); }) await new Promise(async (resolve, reject) => { console.log('開始重建數據表'); await DB.createCollection('session1'); await DB.createCollection('session2'); await DB.createCollection('config'); await DB.createCollection('logs'); await DB.createCollection('message'); await DB.createCollection('other'); await DB.createCollection('user'); await DB.createCollection('video_info'); await DB.createCollection('video_list'); resolve() }) .then(() => { console.log('數據表重建完成'); }) await new Promise(async (resolve, reject) => { console.log('開始建立用戶數據'); // 用戶字段索引 let userColl = DB.collection('user'); // 索引字段 await userColl.createIndexes([ {key:{userName: 1}}, {key:{passWord: 1}}, {key:{display: 1}}, {key:{admin: 1}}, {key:{grade_id: 1}}, {key:{default: 1}} ]); await userColl.insertOne({ userName: 'root', passWord: 'e10adc3949ba59abbe56e057f20f883e', // 123456 md5 nickName: '網站全部者', admin: true, display: true, default: true, grade_id: 2, // 0用戶 1管理員 2root用戶 }); resolve(); }) .then(res=>{ console.log('用戶數據建立成功'); }) });