跳轉至

腳本開發 / 基本概念

DataFlux Func 中,存在一些 DataFlux Func 中特有的概念,本文檔將對此進行説明。

1. 腳本集、腳本和函數

腳本集、腳本和函數可在「開發 / 腳本庫」中創建,是 DataFlux Func 的核心概念,ID 在用户創建 / 編寫代碼時直接指定。

  • 「腳本集」為數個腳本的集合,ID 在創建時由用户直接指定,且只能包含腳本。
  • 「腳本」即 Python 腳本本身,必然屬於某一個腳本集,ID 在創建時由用户直接指定。
  • 「函數」在 DataFlux Func 中特指被 @DFF.API(...) 裝飾器裝飾的最頂層函數,可以被函數 API、定時任務等作為調用的入口函數。

腳本集不是文件夾

腳本集與文件夾類似,但這個「文件夾」與一般 Python 編碼中的文件夾無關

在 DataFlux Func 中進行編碼時,會大量涉及到腳本集、腳本和函數的 ID,並且這些 ID 之間存在緊密的聯繫。

腳本集、腳本和函數 ID 之間關係

按照腳本集、腳本和函數層級關係,下層概念的 ID 一定包含了上層概念的 ID。

假設存在一個 ID 為 demo 的腳本集,那麼屬於此腳本集的所有腳本必然以 demo__(雙下劃線)開頭。

再假設此腳本集下有 ID 為 demo__test的腳本,它包含一個函數 def hello(...),那麼這個函數的 ID 即為 demo__test.hello

ID 示例表如下:

概念 ID 示例
腳本集 demo
腳本 demo__test
函數 demo__test.hello

編碼中相互引用

在 DataFlux Func 的腳本中,允許引用另一腳本來實現代碼複用。

假設存在腳本 demo__script_a,其包含一個函數 func_a()。那麼,在腳本 demo__script_b 中引用此函數時,可以使用如下方法:

demo__script_a
1
2
def func_a():
    pass
demo__script_b
1
2
3
4
import demo__script_b

def test():
    return demo__script_b.func_a()

Python 的as語句也同樣可以使用:

demo__script_b
1
2
3
4
import demo__script_b as b

def test():
    return b.func_a()

也可以使用 from ... import 語句只導入所需函數:

demo__script_b
1
2
3
4
from demo__script_b import func_a

def test():
    return func_a()

對於屬於同一個腳本集的腳本之間引用,可以忽略腳本集 ID,以 __(雙下劃線)開頭的縮略形式表示:

demo__script_b
1
2
3
4
from __script_b import func_a

def test():
    return func_a()

儘可能使用縮略形式

在腳本集內部相互引用應當儘量使用縮略形式(即忽略腳本集 ID 並以 __ 開頭的形式)。

這樣,在將整個腳本集克隆,腳本集 ID 發生改變後,克隆出來的新腳本集內的代碼依然可以正確引用本腳本集內的腳本。

2. 連接器

連接器可在「開發 / 連接器」中創建,是由 DataFlux Func 提供的連接外部系統的工具,ID 在創建時由用户直接指定。

實際上,在 DataFlux Func 編寫 Python 代碼與原版 Python 並無太大區別。開發者完全可以忽略連接器,自行在代碼中連接外部系統。

但對於一些存在連接池概念的外部系統來説,連接器內置了連接池,可在函數反覆運行的過程中保持鏈接,避免反覆創建 / 關閉與外部系統的連接。

假設用户已經配置好了一個 ID 為 mysql 的連接器,那麼獲取這個連接器的操作對象代碼如下:

Python
1
mysql = DFF.CONN('mysql')

具體不同的連接器具有不同的操作方法和參數,詳情請參考 腳本開發 / 連接器對象 DFF.CONN

3. 環境變量

環境變量可在「開發 / 環境變量」中創建,是由 DataFlux Func 提供的簡單 Key-Value 配置讀取工具,ID 在創建時由用户直接指定。

環境變量特別適合用於同一套代碼運行在不同環境下的場景。

如腳本需要訪問的系統區分了測試 / 生產環境,那麼可以通過設置環境變量,實現在不改變代碼的情況下,切換測試 / 生產環境。

假設用户已經配置好了一個 ID 為 api_endpoint 的環境變量,那麼獲取這個環境變量值的代碼如下:

Python
1
api_endpoint = DFF.ENV('api_endpoint')

4. 函數 API

函數 API 可在「管理 / 函數 API」中創建,是外部調用 DataFlux Func 中函數的一種常見方式,調用過程可選同步或異步,同步執行時,函數執行完成後可以將結果直接返回給調用方。

為函數創建函數 API 後,支持多種不同的調用方法。

函數 API 支持 GETPOST 兩種方式。兩種不同方式的參數傳遞同時支持「簡化形式」、「標準形式」。

此外,POST 方式的「簡化」形式還支持文件上傳,以下是各種調用方式的功能支持列表:

調用方式 傳遞 kwargs 參數 kwargs 參數類型 傳遞 options 文件上傳 提交任意格式的 Body
GET 簡化形式 支持 僅限字符串 不支持 不支持 不支持
GET 標準形式 支持 JSON 中的數據類型 支持 不支持 不支持
POST 簡化形式 支持 僅限字符串 不支持 支持 支持
POST 標準形式 支持 JSON 中的數據類型 支持 不支持 不支持

傳遞方式不同會導致參數類型存在限制

對於 kwargs 中參數只能傳遞字符串的調用方式,需要在函數中對參數進行類型轉換。在函數 API 列表,可以點擊「API 調用示例」來查看具體調用方式

假設存在如下函數:

Python
1
2
3
@DFF.API('我的函數')
def my_func(x, y):
    pass

假設為此函數創建的「函數 API」ID 為 func-api-xxxxx,傳遞的參數為 x=100(整數), y="hello"(字符串)。

那麼,各種不同的調用方式如下:

GET 簡化形式傳參

如果函數的參數比較簡單,可以使用 GET 簡化形式傳遞參數,接口將更加直觀。

由於 URL 中傳遞參數時,無法區分字符串的 "100" 和整數的 100, 所以函數在被調用時,接收到的參數都是字符串。 函數需要自行對參數進行類型轉換。

Text Only
1
GET /api/v1/al/func-api-xxxxx/simplified?x=100&y=hello

為了便於閲讀,示例為 URLEncode 之前的內容,實際 URL 參數需要進行 URLEncode

GET 標準形式傳參

在某些情況下,如果無法發送 POST 請求,也可以使用 GET 方式調用接口。

GET 標準形式傳參時,將整個 kwargs 進行 JSON 序列化後,作為 URL 參數傳遞即可。 由於參數實際還是以 JSON 格式發送,因此參數的原始類型都會保留。 函數無需再對參數進行類型轉換。

如本例中,函數接收到的 x 參數即為整數,無需類型轉換。

Text Only
1
GET /api/v1/al/func-api-xxxxx?kwargs={"x":100,"y":"hello"}

為了便於閲讀,示例為 URLEncode 之前的內容,實際 URL 參數需要進行 URLEncode

POST 簡化形式傳參

在某些情況下,如果無法發送請求體為 JSON 的 HTTP 請求, 那麼也可以類似 Form 表單的形式傳遞參數,各字段名即為參數名。

由於 Form 表單提交數據時,無法區分字符串的 "100" 和整數的 100,所以函數在被調用時,接收到的參數都是字符串,函數需要自行對參數進行類型轉換。

Text Only
1
2
3
4
POST /api/v1/al/func-api-xxxxx/simplified
Content-Type: x-www-form-urlencoded

x=100&y=hello

此外,POST 簡化形式傳參還額外支持文件上傳(參數/字段名必須為 files), 需要使用 form-data/multipart 方式進行處理。

頁面 HTML 代碼示例如下:

HTML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<html>
    <body>
        <h1>文件上傳</h1>
        <input id="file" type="file" name="files" required />
        <input id="submit" type="submit" value="上傳"/>
    </body>
    <script>
        // 函數 API 地址(如本頁面與 DataFlux Func 不在同一個域名下,需要寫全 http://domain:prot/api/v1/al/func-api-xxxxx/simplified
        // 注意:上傳文件必須使用簡化形式函數 API
        var API_URL = '/api/v1/al/func-api-xxxxx/simplified';

        document.querySelector('#submit').addEventListener('click', function(event) {
            // 點擊上傳按鈕後,生成 FormData 對象後作為請求體發送請求
            var data = new FormData();
            data.append('x', '100');
            data.append('y', 'hello');
            data.append('files', document.querySelector('#file').files[0]);

            var xhr = new XMLHttpRequest();
            xhr.open('POST', API_URL);
            xhr.send(data);
        });
    </script>
</html>

POST 標準形式傳參

POST 標準形式傳參是最常見的調用方式。 由於參數以 JSON 格式通過請求體發送,因此參數的原始類型都會保留。 函數無需再對參數進行類型轉換。

如本例中,函數接收到的 x 參數即為整數,無需類型轉換。

Text Only
1
2
3
4
5
6
7
8
9
POST /api/v1/al/func-api-xxxxx
Content-Type: application/json

{
    "kwargs": {
        "x": 100,
        "y": "hello"
    }
}

5. 定時任務

定時任務可在「管理 / 定時任務」中創建,用於讓 DataFlux Func 定期自動調用函數。

為函數創建定時任務後,函數則會所指定的 Crontab 表達式定時執行,不需要外部進行調用。

正因為如此,所執行的函數的所有參數必須都已滿足,即:

  1. 函數不需要輸入參數
  2. 函數需要輸入參數,但都是可選參數
  3. 函數需要必選參數,並在定時任務中為其配置具體的值

區分函數運行時所屬執行功能

如果函數同時配置了「定時任務」和其他執行功能,並且希望在不同的執行功能中進行區分處理,可以判斷內置變量 _DFF_CRONTAB 區分:

Python
1
2
3
4
5
6
7
8
9
@DFF.API('我的函數')
def my_func(x, y):
    result = x + y

    if _DFF_CRON_EXPR:
        # 只在定時任務時輸出日誌
        print(f'x + y = {result}')

    return