最近在业务上希望独立出一个任务服务,且在服务重启过程中,不中断任务执行,
看了一下,感觉阿里云函数挺符合场景的,有如下优势,

  1. 通过 HTTP 触发器触发任务
  2. 任务有异步队列机制
  3. 可以指定函数配额
  4. 错误有重试机制
  5. 未执行的任务会使用最新代码执行

任务流程

Image

  1. 通过定时轮询规则表
  2. 创建任务到数据库
  3. 发送任务到阿里云函数,记录请求ID到任务中

注意点

测试中发现,异步任务并没有完全先进先出,
除非使用阿里云的消息队列服务,
不然需要控制任务发送不要超过函数配额

测试代码如下

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"sync"
	"time"
)

func main() {
	url := "https://fc-test-vbhrdreedw.cn-shanghai.fcapp.run"
	now := time.Now()
	client := http.Client{}

	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func(i int) {
			defer wg.Done()

			data := map[string]interface{}{
				"name": "foo",
				"age":  i,
			}
			jsonData, err := json.Marshal(data)
			if err != nil {
				return
			}

			req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(jsonData))
			if err != nil {
				fmt.Println("===> req ", err)
				return
			}
			req.Header.Add("X-Fc-Invocation-Type", "Async")    // 异步调用
			req.Header.Add("Content-Type", "application/json") // 保证参数解析

			token := "token-abc"
			req.Header.Add("Authorization", "Bearer "+token) // Bearer 认证

			resp, err := client.Do(req)
			if err != nil {
				fmt.Println("===> resp ", err)
				return
			}
			requestId := resp.Header.Get("X-Fc-Request-Id")
			fmt.Println("===> requestId ", requestId)
		}(i)
	}
	wg.Wait()
	fmt.Println("===> time ", time.Since(now))
}