Friday, August 7, 2015

Auto restart node daemon: รีสตาร์ทเมื่อแก้ไขซอร์สโค้ด#2

Update: 25/09/2018
-----------------------
หลังจากใช้ pm2 อยู่นาน ไม่ได้เข้าไปวุ่นวายอะไรมากระบบก็ใช้ได้อยู่อย่างนั้นแหละ แต่เมื่อติดตั้งระบบใหม่ Ubuntu เวอร์ชันใหม่ Node.js ก็ใหม่ขึ้น NPM และ PM2 ก็อัพเดทตาม แต่วิธีการเก่ากลับใช้ไม่ได้ผล

ข้อความที่เขียนไว้ด้านล่างนี้ตอนนี้ใช้ไม่ได้ เมื่อเรียกผ่าน json ไฟล์แล้ว เวลาเราเข้าไปดูรายละเอียด pm2 จะหยุดรัน process นั้นๆ ทำให้เว็บเข้าไม่ได้ พยายามแก้ไขอยู่นาน หาอ่านหลายๆ เว็บก็ไม่เจอทางออก

สุดท้ายลองใน DigitalOcean บน Node.js Droplets แล้ว ถ้าเรียกผ่าน command line จะใช้ได้ เช่น

pm2 start app.js --watch
เอาเป็นว่าตอนนี้ใช้แบบนี้ไปก่อนก็แล้วกัน แล้วค่อยตามอัพเดทกันต่อไป

-----------------------
เมื่อวานเขียนเกี่ยวกับ nodemon เพื่อรีสตาร์ท node.js application เมื่อมีการแก้ไขซอร์สโค้ด ก็ถือว่าใช้งานได้ดีระดับหนึ่ง แต่พอลองใช้จริงๆ แล้วกลับเจอปัญหา ด้วยคู่มือและตัวอย่างต่างๆ ก็ยังไม่ละเอียด จึงมองหา Node Monitor ตัวอื่นๆ ก็พบโปรแกรมชื่อ PM2 หรือ Process Monitor สำหรับ node.js โดยลองหาข้อมูลเทียบๆ ดูแล้วหลายคนบอกว่าใช้ได้ดี เหมาะสำหรับติดตั้งระบบจริง

ปัญหาของ nodemon ที่พบ คือ ต้องรันคำสั่ง nodemon <appname>.js ที่ working directory เท่านั้น ถ้ารันผ่าน path จะไม่อัพเดท เช่น nodemon /var/xxx/yyy/<appname>.js เมื่อแก้ไขแล้วจะไม่มีการรีสตาร์ทโพรเซส ปัญหาที่สอง ถึงแม้จะรัน nodemon แบบทำงานเบื้องหลังแล้ว เมื่อทิ้งไว้นาน ลองเข้าไปเช็กด้วยคำสั่ง ps -A | grep node กลับไม่มีโพรเซสของ node.js

แต่ใช่ว่า pm2 จะจบเลย พอสั่งรัน app แล้ว แต่ไม่อัพเดทการแก้ไข เมื่อดูจากคำสั่ง pm2 list แล้วพบว่า watching เป็น disabled ถ้าหน้าจอใครไม่เหมือนตัวอย่างด้านล่าง แสดงว่าเป็นเวอร์ชันเก่าให้ติดตั้งเวอร์ชั่นใหม่ล่าสุดด้วยคำสั่ง
npm install pm2@lastest -g
เมื่อติดตั้งเสร็จ watching ก็ยังไม่เริ่มต้นทำงาน ต้องเขียนคำสั่งเพิ่มเติมก่อนที่จะรันแอพพลิเคชันก่อน

root@tms:# pm2 list
┌──────────┬────┬──────┬─────┬─────────┬─────────┬────────┬────────┬──────────┐
│ App name │ id │ mode │ pid │ status  │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼─────┼─────────┼─────────┼────────┼────────┼──────────┤
│ ticket   │ 0  │ fork │ 0   │ errored │ 28      │ 0      │ 0 B    │ disabled │
└──────────┴────┴──────┴─────┴─────────┴─────────┴────────┴────────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app
root@tms:#


ถ้าต้องการดูรายละเอียดการของ pm2 ให้ใช้คำสั่ง pm2 show <app_name> ซึ่งจะมีรายละเอียดไฟล์ log และอื่นๆ ดังตัวอย่างด้านล่าง

root@tms:# pm2 show ticket
Describing process with id 0 - name ticket
┌───────────────────┬───────────────────────────────────────┐
│ status            │ errored                               │
│ name              │ ticket                                │
│ id                │ 0                                     │
│ path              │ /var/ast/public_html/nodejs/ticket.js │
│ args              │                                       │
│ exec cwd          │ /var/ast/public_html/nodejs           │
│ error log path    │ /root/.pm2/logs/ticket-error-0.log    │
│ out log path      │ /root/.pm2/logs/ticket-out-0.log      │
│ pid path          │ /root/.pm2/pids/ticket-0.pid          │
│ mode              │ fork_mode                             │
│ node v8 arguments │                                       │
│ watch & reload    │                                     │
│ interpreter       │ node                                  │
│ restarts          │ 28                                    │
│ unstable restarts │ 0                                     │
│ uptime            │ 0                                     │
│ created at        │ N/A                                   │
└───────────────────┴──────────── ──────────────────────────┘

root@tms:#

จากนั้นให้เขียนไฟล์ <app_name>.json เอาไว้ที่ใดที่หนึ่งที่ต้องการจะสั่งรัน เช่น หน้าหลักของ user หรือ /root ก็ได้ ตัวอย่างผู้เขียนไว้ที่ home ของ user เป็น inet999 และใช้ชื่อ ticket.json มีรายละเอียดภายในดังนี้
{  "apps": [{    "name": "ticket",    "script": "/var/www/ast/public_html/ticket.js",    "log_file": "/var/log/pm2/ticket.log",    "error_file": "/var/log/pm2/ticket-err.log",    "watch": true,    "ignore_watch": ["files"]  }]}
ที่สำคัญที่สุดคือ สองบรรทัดตัวอักษรสีแดง ที่จะสั่งให้ pm2 เฝ้าดูไฟล์สคริปส์ที่กำหนดไว้ข้างบน จากนั้นก็สั่งรันด้วยคำสั่ง

root@tms:/home/inet999# pm2 start ticket.json
เมื่อเรียบร้อยจะได้ข้อความแสดงรายละเอียดของ App และ pid ดังนี้

[PM2] restartProcessId process id 0
[PM2] restartProcessId process id 1
┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid   │ status │ restart │ uptime │ memory      │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
ticket   │ 0  │ fork │ 28359 │ online │ 14      │ 0s     │ 19.859 MB   │  enabled
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘
 Use `pm2 show <id|name>` to get more details about an app
root@tms:/home/inet99#


เมื่อเรียบร้อยแล้วลองแก้ไขไฟล์สคริปส์แล้ว และรันคำสั่ง pm2 list จะเห็นหมายเลข pid เปลี่ยนแปลงไปเรื่อยๆ จากนั้นลอง ก็ไปกำหนดให้รัน pm2 ทุกครั้งที่มีการรีสตาร์ทเครื่องเซิร์ฟเวอร์ด้วยคำสั่ง

root@tms:~/.pm2/logs# pm2 startup ubuntu
โดยระบบจะสร้างไฟล์เพื่อเปิดโปรแกรม pm2 หลังจากรีสตาร์ทเครื่องดังนี้

[PM2] Generating system init script in /etc/init.d/pm2-init.sh
[PM2] Making script booting at startup...
[PM2] -ubuntu- Using the command:
      su -c "chmod +x /etc/init.d/pm2-init.sh && update-rc.d pm2-init.sh defaults"
 Adding system startup for /etc/init.d/pm2-init.sh ...
   /etc/rc0.d/K20pm2-init.sh -> ../init.d/pm2-init.sh
   /etc/rc1.d/K20pm2-init.sh -> ../init.d/pm2-init.sh
   /etc/rc6.d/K20pm2-init.sh -> ../init.d/pm2-init.sh
   /etc/rc2.d/S20pm2-init.sh -> ../init.d/pm2-init.sh
   /etc/rc3.d/S20pm2-init.sh -> ../init.d/pm2-init.sh
   /etc/rc4.d/S20pm2-init.sh -> ../init.d/pm2-init.sh
   /etc/rc5.d/S20pm2-init.sh -> ../init.d/pm2-init.sh
[PM2] Done.
root@tms:~/.pm2/logs#


และหากต้องการยกเลิกโพรเซสของ pm2 เพื่อที่จะเริ่มต้นใหม่สามารถใช้คำสั่ง 
pm2 kill
สุดท้ายทดสอบด้วยการสั่ง restart เครื่องอีกครั้งหนึ่ง และเข้าไปดูโพรเซส ก็จะเห็นมี node ทำงานอยู่แล้ว และใช้คำสั่ง pm2 list ก็จะเห็นรายละเอียดการเฝ้าติดตามอยู่ (ต้องล็อกอินให้ถูกตามชื่อผู้ใช้งานที่สั่งรัน pm2 ด้วย)

จากไฟล์ ticket.json จะกำหนดไฟล์ log ไว้ใน /var/log/pm2/ticket-0.log ซึ่งเป็นไฟล์ที่เก็บข้อมูลที่ส่งออกมาจาก node.js เราสามารถดูรายละเอียดด้วยคำสั่ง cat หรือ tail -f ก็ได้

ลองดูนะครับ หากมีข้อคิดเห็น ข้อเสนอแนะ หรือมีสิ่งใดผิดพลาดรบกวนช่วยชี้แนะด้วยครับ...

No comments:

Post a Comment