# งานเบื้องหลัง {#jobs}

::: info หน้านี้สอนอะไร
ตั้งงานของคุณเองให้รันตามรอบ (`jobs`) หรือตามเวลาของวันในเขตเวลาของคุณ แล้วดู หยุด หรือเปลี่ยนเวลาได้จาก
**ตั้งค่า → งานเบื้องหลัง**

**ควรอ่านก่อน:** [การเผยแพร่ตามกำหนดเวลา](./drafts#scheduled-publishing)
:::

job คือฟังก์ชันที่ Easy CMS รันพร้อมงานตามกำหนดเวลา: ทุกนาทีบน server ที่รันค้างไว้ (Nuxt, `easy-cms serve`,
Next.js ที่ host เอง) หรือทุกครั้งที่ cron เรียก `<api>/jobs/run` บน serverless (ดู[ใครเป็นคนรันงาน](./drafts#scheduled-publishing))
plugin เพิ่ม job ของตัวเองได้ เช่น ร้านค้าเช็คการชำระเงินทุก 5 นาที

```ts
// easy-cms.config.ts
export default defineConfig({
  // เวลาของวันข้างล่างนี้เป็นเวลาตามเขตนี้ ค่าเริ่มต้น: เขตเวลาของ server (บน serverless มักเป็น UTC)
  timeZone: 'Asia/Bangkok',
  jobs: [
    // ทุก 10 นาที
    { name: 'feed:import', every: 600, run: ({ cms }) => importFeed(cms) },
    // ทุกวันเวลา 02:00 ตามเวลาไทย แอดมินเปลี่ยนเวลารันได้
    { name: 'sitemap:refresh', at: '02:00', adminSchedule: true, run: refreshSitemap },
    // รายสัปดาห์: ทุก 7 วันเวลา 03:00 นับจากครั้งล่าสุดที่รัน
    { name: 'report:weekly', every: 604_800, at: '03:00', run: sendReport },
  ],
})
```

| ตัวเลือก | | |
|---|---|---|
| `name` | **ต้องมี** | ไม่ซ้ำกัน ตัวพิมพ์เล็ก เช่น `shop:clean-up` |
| `run` | **ต้องมี** | `({ cms, now }) => …` ถ้า throw error จะถูกบันทึกลง log และแสดงในหน้างานเบื้องหลัง |
| `every` | ทุกครั้งที่รัน | ถี่ที่สุดเท่านี้ หน่วยเป็นวินาที ถ้ามี `at` ต้องเป็นจำนวนวันเต็ม (ค่าเริ่มต้นคือหนึ่งวัน) |
| `at` | — | เวลาของวัน `HH:MM` ตาม `timeZone` |
| `adminSchedule` | `false` | ให้แอดมินเปลี่ยน `every` และ `at` ได้จากหน้างานเบื้องหลัง |

**รอบที่พลาดไป** ถ้าถึงเวลาแล้วไม่มีอะไรรันงาน (server ปิดอยู่ หรือ cron มาช้า) งานจะรันหนึ่งครั้งทันทีที่งานกลับมารัน
แล้วกลับไปรันตามรอบปกติ

**หลาย instance** ทุกรอบของงานถูกจองในฐานข้อมูลก่อนเริ่ม งานจึงรันครั้งเดียวตามเวลา ไม่ว่าจะมีกี่ server
(หรือ scheduler กับ cron ทำงานพร้อมกัน) แต่ควรเขียนงานให้รันซ้ำได้โดยไม่เสียหาย เพราะรอบที่หยุดกลางทาง
(เช่น server ล่ม หรือ deploy) จะไม่รันใหม่จนกว่าจะถึงรอบถัดไป

**เขตเวลา** ใช้กับ [`backups.at`](./backups) ด้วย

## ตั้งค่า → งานเบื้องหลัง {#settings-jobs}

แอดมินและ[บทบาท](./roles)ที่ได้สิทธิ์ **งานเบื้องหลัง** จะเห็นทุกงาน พร้อมรอบการรัน รันล่าสุดเมื่อไรและใช้เวลานานเท่าไร
ผลล่าสุด (พร้อมข้อความ error ถ้าไม่สำเร็จ) และรอบถัดไป อีก tab แสดง[การเผยแพร่ตามกำหนดเวลา](./drafts#scheduled-publishing)
ที่รอ กำลังรัน หรือไม่สำเร็จ ปุ่ม **รันงานที่ถึงเวลาเดี๋ยวนี้** รันทุกอย่างที่ถึงเวลาเหมือนที่ cron ทำ

หน้านี้ยังบอกว่างานเบื้องหลังรันล่าสุดเมื่อไร และเตือนถ้าไม่มีอะไรรันเลยเกิน 10 นาที (บน serverless มักเป็นเพราะไม่ได้ตั้ง cron)
ส่วน **งานในตัวระบบ** แสดงสิ่งที่ Easy CMS ทำทุกรอบ ได้แก่ การเผยแพร่ตามกำหนดเวลา, ส่ง webhook และอีเมลซ้ำ,
สำรองข้อมูลตามเวลา และตรวจ audit log พร้อมลิงก์ไปหน้าของแต่ละงาน

แอดมินของทั้งระบบทำได้อีก:

- **หยุด** งาน เช่น ตอนที่บริการภายนอกที่งานเรียกใช้ล่มอยู่ งานจะไม่รันจนกว่าจะมีคนกด **ทำต่อ**
  และ Dashboard จะแสดงไว้ใน **ต้องดูแล** กันลืม
- **เปลี่ยนเวลารัน** ของงานที่มี `adminSchedule` ทั้งความถี่และเวลาของวัน การ์ดจะบอกว่าตั้งโดยแอดมิน
  และแสดงค่าใน config ไว้เทียบ ปุ่ม **ใช้ค่าใน config** จะกลับไปใช้ค่าเดิม งานที่ไม่มี `adminSchedule`
  ใช้เวลาตามโค้ดเสมอ เพราะอาจสำคัญ (การเช็คการชำระเงินของร้านค้าต้องรันถี่)

การหยุด ทำต่อ และการเปลี่ยนเวลาถูกบันทึกใน [audit log](./audit-log) งานที่รันล่าสุดไม่สำเร็จจะขึ้นบน Dashboard ด้วย
ดู[ตรวจสุขภาพระบบ](./health-checks#failed-jobs)

## ขั้นต่อไป {#next-steps}

- [การเผยแพร่ตามกำหนดเวลา](./drafts#scheduled-publishing): เผยแพร่และยกเลิกเผยแพร่ตามเวลาที่ตั้งไว้
- [ตรวจสุขภาพระบบ](./health-checks): สิ่งที่ Dashboard เตือนแอดมิน
- [Plugin](./plugins): เพิ่ม job จาก plugin
