# การโอนวอลเล็ตกับผู้ให้บริการ API: ไม่ให้คิวคำขออุดตัน

> การเรียกโอนเงินต่อกันเป็นทอด ๆ ระหว่างแพลตฟอร์มกับผู้ให้บริการ API ทำให้คิวคำขอล้นได้อย่างไร และคิว การตอบกลับเร็ว และการพุชผลลัพธ์ช่วยให้แพลตฟอร์มเสถียรแม้ผู้ให้บริการช้าได้อย่างไร

Source: https://hibira.io/th/topics/wallet-transfers-api-providers
Updated: 2026-11-09

แพลตฟอร์มดูแลวอลเล็ตของผู้ใช้ ส่วนผู้ให้บริการ API รันเซิร์ฟเวอร์ที่อยู่เบื้องหลังบริการที่แพลตฟอร์มนำเสนอ ก่อนผู้ใช้จะใช้บริการของผู้ให้บริการรายใด เงินจะย้ายจากแพลตฟอร์มไปยังผู้ให้บริการ และเมื่อใช้เสร็จก็ย้ายกลับ การเชื่อมต่อส่วนใหญ่สร้างการโอนนี้เป็นสายโซ่ของการเรียก HTTP แบบซิงโครนัสทั้งสองทิศทาง เมื่อโหลดสูง สายโซ่นี้ทำให้คิวคำขอของทั้งสองฝั่งเต็ม และผู้ให้บริการที่ช้าเพียงรายเดียวก็ลากทั้งแพลตฟอร์มล่มตามได้ ความเสถียรของแพลตฟอร์มคุณไม่ควรขึ้นกับเซิร์ฟเวอร์ของคนอื่น

## การโอนหนึ่งครั้งคือสายโซ่ของคำขอ

```text
sequence: ก่อน: การโอนหนึ่งครั้ง ทำด้วยสายโซ่การเรียก HTTP
ผู้ใช้ | แพลตฟอร์ม | ผู้ให้บริการ API
1 > 2: เริ่มใช้บริการ | worker ของแพลตฟอร์มรอ
2 > 3: POST /transfer-in | รอผู้ให้บริการ
3 > 2: GET /wallet/verify | worker ของผู้ให้บริการก็รอ
2 >> 3: 200 OK
3 >> 2: 200 | หรือหมดเวลา ไม่รู้สถานะ
2 > 3: GET /transfer/123 | ทุก 2 วินาทีจนเสร็จ
2 >> 1: พร้อมแล้ว
```

worker ของแพลตฟอร์มถูกยึดตลอดการเดินทางไปกลับ รวมถึงช่วงที่ผู้ให้บริการเรียกกลับมาที่แพลตฟอร์ม worker ของผู้ให้บริการถูกยึดระหว่างรอการเรียกกลับนั้น ต่างฝ่ายต่างรอกัน เมื่อทราฟฟิกขึ้น พูลของทั้งสองฝั่งจึงเต็มพร้อมกัน การหมดเวลาครั้งเดียวทำให้ไม่รู้สถานะการโอน ตามมาด้วยการโพลสถานะและการลองใหม่ และถ้าไม่มี idempotency key การลองใหม่อาจโอนเงินซ้ำสองครั้ง

## ผู้ให้บริการที่ช้ารายเดียวกลายเป็นปัญหาของทุกคนได้อย่างไร

```text
flow: ความช้าชั่วขณะกลายเป็นคำขอท่วม
โปรโมชันเริ่ม|การโอนเพิ่มขึ้น --> ผู้ให้บริการ C ช้าลง|150 ms → 5 วินาที --> worker แพลตฟอร์มถูกยึด|รอ C อยู่ --> พูลที่ใช้ร่วมกันหมด|ทุกคำขอต้องรอคิว
คำขอหมดเวลา --> ลองใหม่และโพลสถานะ|คำขอเพิ่มขึ้นอีก --> ล็อกอิน การเติมเงิน และผู้ให้บริการอื่นล้ม|ไม่เกี่ยวกับ C
```

นี่คือตัวอย่างการคำนวณ ไม่ใช่ผลการทดสอบ (เขียนเมื่อ 2026-11-09): การโอน 500 ครั้งต่อวินาที กระจายไปสามผู้ให้บริการ และพูลของแพลตฟอร์มมี 200 worker [กฎของลิตเติล](https://en.wikipedia.org/wiki/Little%27s_law)ให้จำนวน worker ที่ใช้งาน: การโอนต่อวินาที × วินาทีที่แต่ละครั้งยึด worker

| | HTTP ต่อกันเป็นทอด ๆ | คิว รับเร็ว และพุชผลลัพธ์ |
| --- | --- | --- |
| เวลาที่คำขอของผู้ใช้ยึด worker ของแพลตฟอร์ม | 20 ms + การเรียกผู้ให้บริการ 150 ms = 170 ms | 20 ms |
| worker ที่ไม่ว่างที่ 500 การโอนต่อวินาที | 500 × 0.17 วินาที = 85 | 500 × 0.02 วินาที = 10 |
| ผู้ให้บริการหนึ่งในสามค้างจนหมดเวลา 5 วินาที | ประมาณ 900: พูล 200 หมด และผู้ให้บริการทุกรายล้ม | ยังคง 10: รอเฉพาะการโอนของผู้ให้บริการรายนั้น |
| คำขอระหว่างรอผลลัพธ์ | โพลสถานะทุก 2 วินาทีต่อการโอนที่ค้างอยู่ | ไม่มี มีเพียงการตรวจแบบชุดต่อผู้ให้บริการทุกไม่กี่นาที |

## หลัง: รับเร็ว ชำระเบื้องหลัง แล้วพุชผลลัพธ์

```text
sequence: หลัง: ทั้งสองฝั่งตอบเร็ว และผลลัพธ์มาถึงเป็นอีเวนต์
ผู้ใช้ | แพลตฟอร์ม | ผู้ให้บริการ API | *Hibira
1 > 2: เริ่มใช้บริการ
2 >> 1: กำลังดำเนินการ | บันทึกบัญชีแล้ว ปล่อย worker
2 > 3: POST /transfers | idempotency key ส่งจากคิว
3 >> 2: 202 Accepted | บันทึกแล้ว ปล่อย worker
note: ผู้ให้บริการชำระจากคิวของตัวเอง ตามจังหวะของตัวเอง
3 > 4: transfer.settled | private-partner-acme
4 > 2: transfer.settled | id 123 จำนวนเงิน
2 > 4: balance.updated | private-wallet-42
4 > 1: balance.updated
```

1. **แพลตฟอร์มตอบผู้ใช้ก่อน** บันทึกการโอนลงบัญชีแยกประเภทเป็นสถานะกำลังดำเนินการ ใส่คิว แล้วตอบกลับ หน้าของผู้ใช้แสดง "กำลังดำเนินการ" และอัปเดตเองเมื่ออีเวนต์มาถึง
2. **ตัวส่งงานส่งการโอนไปยังผู้ให้บริการแต่ละราย** พร้อม idempotency key การหมดเวลาแบบสั้น และจำนวนช่องที่กำหนดตายตัวต่อผู้ให้บริการ ผู้ให้บริการตอบ 202 ทันทีที่บันทึกการโอน การลองใหม่ด้วยคีย์เดิมจึงปลอดภัยเสมอ
3. **ไม่มีการเรียกกลับ** คำขอมีทุกอย่างที่ผู้ให้บริการต้องใช้พร้อมลายเซ็น ผู้ให้บริการจึงไม่ต้องเรียกกลับมาที่แพลตฟอร์มเพื่อตรวจสอบ
4. **ผลลัพธ์ถูกพุช** ผู้ให้บริการเผยแพร่ `transfer.settled` ไปยังแชนเนลส่วนตัวสำหรับแพลตฟอร์มนั้น เช่น `private-partner-acme` แบ็กเอนด์ของแพลตฟอร์มเปิดการเชื่อมต่อ WebSocket ไว้หนึ่งเส้นและสมัครรับ โดยได้รับสิทธิ์จาก endpoint ยืนยันสิทธิ์ของผู้ให้บริการ จากนั้นอัปเดตบัญชีและเผยแพร่ `balance.updated` ไปยังแชนเนลวอลเล็ตของผู้ใช้ เหมือนใน[การซิงก์ยอดเงินระหว่างผลิตภัณฑ์](https://hibira.io/th/topics/balance-sync-websocket)
5. **ตรวจครั้งเดียวสำหรับสิ่งที่พลาด** ทุกไม่กี่นาที แพลตฟอร์มถามผู้ให้บริการแต่ละรายถึงการโอนที่ยังค้าง ด้วยคำขอแบบชุดเดียว แทนการโพลทีละการโอน

## ให้แพลตฟอร์มเสถียรแม้ผู้ให้บริการไม่เสถียร

- **แยกช่องให้ผู้ให้บริการแต่ละราย** ผู้ให้บริการที่ช้าลงจะเต็มเฉพาะช่องของตัวเองในตัวส่งงาน ล็อกอิน การเติมเงิน และผู้ให้บริการอื่นยังมี worker ของตัวเอง
- **หยุดส่งให้ผู้ให้บริการที่ไม่ตอบ** หลังหมดเวลาติดกันหลายครั้ง ให้หยุดคิวของผู้ให้บริการรายนั้น แสดงบริการของเขาว่าใช้ไม่ได้ชั่วคราว แล้วลองใหม่หลังรอสักครู่ การโอนรออยู่ในบัญชีของคุณในสถานะกำลังดำเนินการ ไม่ใช่ในการเชื่อมต่อที่ถูกยึด
- **WebSocket หลุดก็ไม่มีอะไรติดขัด** การโอนยังรับต่อไปได้ เมื่อการเชื่อมต่อกลับมา การตรวจแบบชุดจะชำระสิ่งที่เกิดขึ้นในระหว่างนั้น
- **ผู้ใช้ไม่ต้องรอเวลาตอบของผู้ให้บริการ** หน้าเว็บตอบตามความเร็วของแพลตฟอร์มเอง และผลลัพธ์ปรากฏเมื่อพร้อม

## คำถามที่พบบ่อย

### ทำไมผู้ให้บริการ API ที่ช้ารายเดียวทำให้ทั้งแพลตฟอร์มช้า?

เพราะ worker ของแพลตฟอร์มรอผู้ให้บริการรายนั้น การเรียกแบบซิงโครนัสยึด worker ไว้จนกว่าผู้ให้บริการจะตอบ และ worker เหล่านั้นใช้ร่วมกับทุกอย่าง เมื่อผู้ให้บริการรายหนึ่งช้าลง worker ก็หมด และคำขอที่ไม่เกี่ยวกับผู้ให้บริการรายนั้นเลยก็ต้องต่อคิวตาม

### WebSocket มาแทน API การโอนหรือไม่?

ไม่ การโอนเองยังเป็นคำขอ HTTP พร้อม idempotency key และบันทึกในบัญชีของทั้งสองฝั่ง WebSocket มาแทนการรอ คือการเชื่อมต่อที่ถูกยึด การโพลสถานะ และการเรียกกลับ ผลลัพธ์มาถึงเป็นอีเวนต์แทน

### ถ้าแพลตฟอร์มหลุดการเชื่อมต่อตอนที่การโอนชำระเสร็จล่ะ?

ไม่มีอะไรหาย เพราะบัญชีของทั้งสองฝั่งบันทึกการโอนไว้แล้ว pusher-js และไลบรารีไคลเอนต์อื่น ๆ เชื่อมต่อใหม่เอง และการตรวจแบบชุดของการโอนที่ค้างจะชำระสิ่งที่พลาดไป ใช้ ID ของการโอนเพื่อข้ามอีเวนต์ที่ใช้ไปแล้ว

### ต้องใช้การเชื่อมต่อกี่เส้น?

การเชื่อมต่อ WebSocket หนึ่งเส้นจากแบ็กเอนด์ของแพลตฟอร์มไปยังแชนเนลของผู้ให้บริการแต่ละราย ก็พอสำหรับทุกการโอนกับผู้ให้บริการรายนั้น ไม่ว่าจะให้บริการผู้ใช้กี่คน บน Hibira การเผยแพร่หนึ่งครั้งนับเป็นหนึ่งข้อความ และแผนแบบชำระเงินไม่นับการส่งถึงผู้สมัครรับ ดู[ราคา](https://hibira.io/th/pricing)
