# Step

### How To Use

Packhouse本體只是個函數設計模型，而Step負責建構`middleware`與流程設計使得Packhouse具有實際建構服務的能力。

Step是一個[Plugin](https://packhouse-doc.metalsheep.com/the-instance/plugin)，使用前必須先引用：

```javascript
let Step = require('packhouse/plugins/Step')
let Packhouse = require('packhouse')
let packhouse = new Packhouse()

packhouse.plugin(Step)
```

{% hint style="info" %}
與其說本頁面是教學更像是說明文件，實際的應用方式可以直接參照[API Service](https://packhouse-doc.metalsheep.com/application/api-service)。
{% endhint %}

## Flow

整個flow是經由下列控制：

* `next`下一步。
* `exit`跳出至`output`，可以攜帶一個參數，會傳遞至`output`的`message`。
* `fail`跳出至`output`，但`fail`為`true`，可以攜帶一個參數，會傳遞至`output`的`message`。

```javascript
let step = packhouse.step({
    timeout: 25000, // ms
    create: function(self, { exit, fail }) {
        self.result = 0
    },
    middle: function(self, { exit, fail }) {
        if (typeof self.result !== 'number') {
            exit()
        }
    },
    // required
    output(self, { timeout, history, fail, message }, done, error) {
        done(self.result)
    },
    // required
    template: [
        function add(self, next, { exit, fail }) {
            self.result = 10
            next()
        },
        function double(self, next) {
            self.result *= 2
            next()
        }
    ]
})

step.then((result) => {
    console.log(result) // 20
})
```

上面的程式的運作如下：

<div align="left"><img src="https://4135423742-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LwD6MjHg3yMxWgKGDEI%2F-LwY_lq11kEvPv_LGQoZ%2F-LwYsJGuPwnxtz_0NXex%2FUntitled%20Diagram%20(4).png?alt=media&#x26;token=9ede6fd5-7b1d-4f82-bec1-ee8e441df46d" alt=""></div>

### Create

第一次執行Step時觸發的方法，必須是同步的函數，可以執行跳出事件。

### Middle

`create -> template -> output` 行為之間都會出發`middle`，可以作為跳出判定層，必須是同步函數。

### Output

接收所有運算結果的地方，為非同步函數，最後兩個參數為`done`與`error`，決定整個Step為`reslove`還是`reject`。

```javascript
const output = (self, { timeout, history, fail, message }, done, error) => {
    done('success!')
}
```

### Timeout

指定運行的毫秒數，如果省略則無限制，當運行時間超過時會無條件呼叫`output`，且`timeout`為`true`。

{% hint style="info" %}
由於`output`有可能需要處裡請求事件，Timeout的設計並不包含該流程的時間，在AWS APIGateway開發的過程需要注意只能運行30秒的限制。
{% endhint %}

```javascript
const output = (self, { timeout}, done, error) => {
    console.log(timeout) // true or false
}
```

### Fail

當呼叫`output`的對象是`fail`時為`true`。

### Message

當`fail`或`exit`有攜帶參數時會帶入的值。

### Template

運作的過程，與[`async waterfall`](https://caolan.github.io/async/v3/docs.html#waterfall)雷同，會隨著陣列的順序依序宣告，執行到最末端後執行`output`，也允許執行跳出整個流程。

### History

記錄整個執行過程的物件，可輸出`JSON Log`。

```javascript
{
    profile: 'object',
    template: 'template log',
    isDone: 'function',
    toJSON: 'function'
}
```

#### Profile

| Key        | Value           |
| ---------- | --------------- |
| fail       | 是否為Fail         |
| message    | 同output message |
| timeout    | 是否為timeout      |
| startTime  | 起始時間            |
| finishTime | 結束時間            |
| totalTime  | 總運行時間(ms)       |

#### Template

整體運作的細部資料，除非不得已，否則我們建議使用[ToJSON](#to-json)來檢視整個過程。

#### Is Done

如果有對Template的函數進行命名，可以使用`isDone`來驗證是否有運行該函數。

```javascript
const step = {
    template: [
        function myFunction(self, next, { exit }) {
            exit()
        },
        function myFunction2(self, next) {
            next()
        }
    ],
    output(self, { history }, done) {
        console.log(history.isDone('myFunction')) // true
        console.log(history.isDone('myFunction2')) // false
        done()
    }
}
```

#### To JSON

將細部運作資料轉換成JSON可存放資料。

{% hint style="info" %}
輸出的資料將是個大型的JSON文件，尤其是在參數與回傳值非常龐大的情況下，請自行評估何時運作`toJSON`來確保是否佔用太多資源。
{% endhint %}

```javascript
let Step = require('packhouse/plugins/Step')
let Packhouse = require('packhouse')
let packhouse = new Packhouse()

packhouse.plugin(Step)
packhouse.addGroup('math', () => {
    return {
        data: {
            tools: {
                sum: {
                    handler(self, v1, v2) {
                        self.success(v1 + v2)
                    }
                }
            }
        }
    }
})

packhouse.step({
    template: [
        function sum(self, done) {
            packhouse.tool('math/sum').action(10, 20, () => {
                done()
            })
        }
    ],
    output(self, { history }, done) {
        console.log(history.toJSON({
            hello: 'world'
        }))
        done()
    }
})

// 以下是輸出的JSON

{
    "profile": {
        "fail": false,
        "timeout": false,
        "startTime": 1577071246765,
        "finishTime": 1577071246769,
        "totalTime": 4
    },
    "metadata": {
        hello: 'world'
    },
    "template": [
        {
            "name": "sum",
            "logs": {
                "5f0e1c0e-e537-42f3-ab3b-cc6689aada5e": {
                    "logs": {},
                    "startTime": 1577071246768,
                    "name": "sum",
                    "args": [
                        10,
                        20
                    ],
                    "caller": null,
                    "mode": "action",
                    "request": "[]",
                    "response": null,
                    "group": {
                        "name": "math",
                        "sign": ""
                    },
                    "success": true,
                    "result": 30,
                    "finishTime": 1577071246768,
                    "totalTime": 0
                }
            },
            "startTime": 1577071246766,
            "finishTime": 1577071246768,
            "totalTime": 2
        }
    ]
}
```

我們提供了簡易的JSON Template檢視工具來協助你開發：

[History檢視工具](https://khc-zhihao.github.io/Packhouse/tools/step-view/)
