Когда я создаю более мощные последовательности в OpenWhisk, одна из проблем, с которыми я сталкиваюсь, заключается в том, как обрабатывать маршрутизацию в последовательностях. По сути, при заданной последовательности A=›B=›C=› могут быть случаи, когда:

  • B может выдать ошибку
  • B может быть все, что мне нужно сделать, и мы можем пропустить C
  • A решает, что хочет пропустить B
  • B может выдать ошибку, но я хочу продолжить попытки некоторое время

Все это технически осуществимо, но не обязательно просто в настройке. Помните, что для работы с OpenWhisk существует пакет Node. Теоретически я мог бы создать действие, которое использует этот пакет и делает все вышеперечисленное непосредственно в коде. Но что меня больше интересует, так это то, как это можно настроить на «мета» уровне. По сути, я хочу сделать все это абстрактным образом и оставить свои действия в виде чистого кода.

К сожалению, то, что я описал выше, пока не совсем возможно, но вы можете приблизиться к этому с помощью пакета Combinators. В то время, когда я пишу это, пакет combinators не задокументирован в справочнике, но вы можете получить информацию о пакете, используя:

wsk package get --summary /whisk.system/combinators

Вместо того, чтобы копировать и вставлять результат, я его немного отформатирую. Вот действия:

  • /whisk.system/combinators/eca Событие-Условие-Действие: запустить действие по условию и если результат успешен, запустить действие. (параметры: $actionName, $conditionName)
  • /whisk.system/combinators/retry Повторяйте попытку вызова действия до тех пор, пока количество успешных попыток или попыток не будет исчерпано, в зависимости от того, что наступит раньше. (параметры: $actionName, $attempts)
  • /whisk.system/combinators/forwarder Перенаправить параметры вокруг другого действия. (параметры: $actionArgs, $actionName, $forward)
  • /whisk.system/combinators/trycatch Оборачивает действие с помощью try-catch. Если действие завершается ошибкой, вызывает второе действие для обработки ошибки. (параметры: $catchName, $tryName)

Сегодня я сосредоточусь на действии trycatch. Как сказано в описании, он оборачивает действие и позволяет вызывать действие при возникновении ошибки. Итак, представьте это действие:

function main(args) {

    if(args.error == null) args.error = false;

    if(!args.error) {
        return {result:1}
    } else {
        throw new Error('Oh Crap');
    }

}

Как вы можете видеть, он принимает только один аргумент, ошибку, и если он верен, он выдает ошибку. Запустим:

wsk action invoke safeToDelete/divide -b

И результат. (Кстати, не обращайте внимания на название «разделение» — я думал сделать что-то еще.)

{
    "activationId": "bcf71f2dae4e464a9541638728468e11",
    "annotations": [
        {
            "key": "limits",
            "value": {
                "logs": 10,
                "memory": 256,
                "timeout": 60000
            }
        },
        {
            "key": "path",
            "value": "[email protected]_My Space/safeToDelete/divide"
        }
    ],
    "duration": 18,
    "end": 1495808497997,
    "logs": [],
    "name": "divide",
    "namespace": "[email protected]_My Space",
    "publish": false,
    "response": {
        "result": {
            "result": 1
        },
        "status": "success",
        "success": true
    },
    "start": 1495808497979,
    "subject": "[email protected]",
    "version": "0.0.6"
}

А теперь попробуем с ошибкой. Сначала звонок:

wsk action invoke safeToDelete/divide -b --param error true

Тогда результат:

{
    "activationId": "3804923a0b1540caa9027ad974045a43",
    "annotations": [
        {
            "key": "limits",
            "value": {
                "logs": 10,
                "memory": 256,
                "timeout": 60000
            }
        },
        {
            "key": "path",
            "value": "[email protected]_My Space/safeToDelete/divide"
        }
    ],
    "duration": 11,
    "end": 1495808578214,
    "logs": [],
    "name": "divide",
    "namespace": "[email protected]_My Space",
    "publish": false,
    "response": {
        "result": {
            "error": "An error has occurred: Error: Oh Crap"
        },
        "status": "action developer error",
        "success": false
    },
    "start": 1495808578203,
    "subject": "[email protected]",
    "version": "0.0.6"
}

Хорошо — почти так, как и ожидалось. Итак, теперь давайте попробуем действие trycatch. Он принимает два аргумента — имя действия, которое нужно попробовать, и имя действия, которое нужно выполнить при ошибке. Вот как бы вы это назвали:

wsk action invoke /whisk.system/combinators/trycatch --param '$tryName' /_/safeToDelete/divide --param '$catchName' /_/safeToDelete/error -b

Обратите внимание на несколько вещей здесь. Использование /_/ является псевдонимом моего пространства имен. Действие комбинатора не выполняется в моем локальном пространстве имен, поэтому это помогает сообщить ему, где существуют действия. Я мог бы сделать связанную копию экшена, чтобы иметь собственную копию, но в этом нет необходимости. Затем обратите внимание на одинарные кавычки вокруг параметров. Когда я забыл их, у моей оболочки были проблемы со знаками доллара перед параметрами. Спасибо Carlos Santana (еще раз) за помощь. При запуске вывод будет таким же (технически не то же самое, метаданные другие, но результат тот же).

{
    "activationId": "bd67ad9ce7904ed5b2e73dc1fb9ddc52",
    "annotations": [
        {
            "key": "limits",
            "value": {
                "logs": 10,
                "memory": 256,
                "timeout": 60000
            }
        },
        {
            "key": "path",
            "value": "whisk.system/combinators/trycatch"
        }
    ],
    "duration": 257,
    "end": 1495808743463,
    "logs": [],
    "name": "trycatch",
    "namespace": "[email protected]_My Space",
    "publish": false,
    "response": {
        "result": {
            "result": 1
        },
        "status": "success",
        "success": true
    },
    "start": 1495808743206,
    "subject": "[email protected]",
    "version": "0.0.36"
}

И вот пример, где мы форсируем ошибку. Опять же, сначала вызов:

wsk action invoke /whisk.system/combinators/trycatch --param '$tryName' /_/safeToDelete/divide --param '$catchName' /_/safeToDelete/error -b --param error true

А потом результат:

{
    "activationId": "19e301526ab24bd59dc01f6814eb46fb",
    "annotations": [
        {
            "key": "limits",
            "value": {
                "logs": 10,
                "memory": 256,
                "timeout": 60000
            }
        },
        {
            "key": "path",
            "value": "whisk.system/combinators/trycatch"
        }
    ],
    "duration": 764,
    "end": 1495808966619,
    "logs": [],
    "name": "trycatch",
    "namespace": "[email protected]_My Space",
    "publish": false,
    "response": {
        "result": {
            "status": "Um a very bad thing just happened - sorry?"
        },
        "status": "success",
        "success": true
    },
    "start": 1495808965855,
    "subject": "[email protected]",
    "version": "0.0.36"
}

Обратите особое внимание на статус. Теперь результат отмечен как успешный. Моя ошибка возникла из-за действия, которое я создал для ее обработки:

function main(args) {
    console.log('error action', JSON.stringify(args));

    return {status:"Um a very bad thing just happened - sorry?"};

}

Очевидно, я мог бы сделать здесь немного больше, но вы поняли основную идею. Это также может быть добавлено как часть большей последовательности. К сожалению, нет хорошего способа справиться с «A, B и, возможно, остановиться или перейти к C». Действие eca близко, но требует, чтобы вы выдали ошибку в B, что, на мой взгляд, неправильно. Хорошей новостью является то, что скоро в этом пространстве появятся некоторые улучшения. Следите за обновлениями в моем блоге. :)

Первоначально опубликовано на www.raymondcamden.com 26 мая 2017 г.