SaaS分野におけるサーバーレスのベストプラクティス

インターネット人口動態の配当が徐々に減少し、トラフィックベースの成長が鈍化する中、インターネット業界は、自らの継続的な成長をサポートできる新しい青い海を早急に見つける必要があります。産業用インターネットは、この壮大な状況における新しいトレンドです。インターネットの波が従来の業界を席巻していることがわかります。クラウドコンピューティング、ビッグデータ、人工知能が、金融、製造、ロジスティクス、小売、エンターテインメント、教育、医療業界の生産リンクに大規模に統合され始めています。この統合は、インダストリアルインターネットと呼ばれます。 。インダストリアルインターネットでは、過小評価できない領域の1つがSaaSフィールドです。これは、CRM、HRM、経費管理システム、金融システム、共同オフィスなど、ToBトラックの中間的な力です。

SaaSシステムが直面する課題

消費者向けインターネットの時代では、誰もが欲しいものを探しています。さまざまなメーカーが、クラウドコンピューティング、ビッグデータ、人工知能などのテクノロジーに基づいてトラフィックを最大化するサービスとエコシステムを構築し、大量のコンテンツ配信とトラフィック共有のロジックに基づいてシステムを構築しています。 。インダストリアルインターネットの時代に、供給関係は変化しました。誰もが自分の望むものをカスタマイズしています。双方向の構築は、供給と需要の両側から実行する必要があります。現在、システムの柔軟性と拡張性は、前例のない課題、特にToBに直面しています。 SaaSフィールド。

特に現在の経済環境では、SaaSベンダーは、もはやお金を燃やすことができず、自分のユーザーの数だけに焦点を当てることができることを理解する必要があります。また、顧客がコストを削減して効率を高める方法についてもっと考える必要があります。製品のカスタマイズ機能に焦点を当てます。

課題への対処方法

SaaS分野のリーダーであるSalesforceは、CRMの概念をマーケティング、セールス、サービスにまで拡張しています。これら3つの分野のうち、専門のSaaS製品を持っているのはセールスだけです。他の2つの分野は、さまざまな業界のISV向けの業界ソリューションです。それは何に依存していますか?間違いなく、これはSalesforceの強力なaPaaSプラットフォームです。ISV、内部実装、および顧客はすべて、aPaaSプラットフォームを使用して、それぞれの次元の独自の業界および分野でSaaSシステムを構築し、完全なエコシステムを確立できます。したがって、私の意見では、現在のSalesforceはSaaS会社からaPaaSプラットフォーム会社にアップグレードされています。この進化的なプロセスは、消費者向けインターネットと産業用インターネットの間の移行ロジックと、後者のコア需要も確認します。

ただし、すべてのSaaS企業がaPaaSプラットフォームをインキュベートして磨くための財源と時間を持っているわけではありませんが、市場の変化とユーザーの要求は現実のものです。生き残るためには、変化が必要です。この変更の核となるのは、現在のSaaSシステムを柔軟にすることです。難しいaPaaSプラットフォームと比較して、実際には軽量で効果的なサーバーレスソリューションを選択して、既存のシステムの柔軟性とスケーラビリティを向上させることができます。ユーザーのさまざまなカスタマイズのニーズ。

サーバーレスワークフロー

前回の記事「リソースコストの二重最適化!「プログラミング教育の革新的実践のサーバーレス転覆を参照」では、サーバーレスの概念が説明され、サーバーレス機能コンピューティング(FC)の概念と実践も紹介されています。この記事では、システムの柔軟性を構築するためのコア要素サービスの振り付け-サーバーレスワークフローを紹介します。

サーバーレスワークフローは、複数の分散タスクの実行を調整するために使用されるフルマネージドクラウドサービスです。サーバーレスワークフローでは、分散タスクを順番に、分岐して、並列に配置できます。サーバーレスワークフローは、設定された手順に従ってタスクの実行を確実に調整し、各タスクの状態遷移を追跡し、必要に応じて実行します。再試行ロジックを定義して、ワークフローがスムーズに完了するようにします。サーバーレスワークフローは、アプリケーションを簡単に診断およびデバッグできるロギングと監査を提供することにより、ワークフローの実行を監視します。

次の図は、サーバーレスワークフローが分散タスクを調整する方法を示しています。これらのタスクは、関数、統合クラウドサービスAPI、および仮想マシンまたはコンテナーで実行されるプログラムです。

サーバーレスワークフローの紹介を読んだ後、いくつかのアイデアがあるかもしれません。システムの柔軟性とスケーラビリティの中核は、以前のBPMであろうと現在のaPaaSであろうと、サービスのオーケストレーションです。したがって、サーバーレスワークフローに基づいてSaaSシステムの柔軟性を再構築するという中心的なアイデアは、ユーザーがシステム内で最もカスタマイズしたい機能を分類、分割、抽出し、機能コンピューティング(FC)と連携してステートレス機能を提供することです。ワークフローは、これらの機能ポイントを配置して、さまざまなビジネスプロセスを実現します。

機能計算FCとサーバーレスワークフローを通じて柔軟な食事注文モジュールを構築する

注文シーンは誰もが知っていると思いますが、自宅での注文やレストランでの注文はすべてこのシーンに関係しています。注文システムを提供するSaaSサービスベンダーも多数あり、優れたSaaS注文システムも多数あります。コンシューマーインターネットからインダストリアルインターネットへの移行に伴い、これらのSaaS注文システムはますますカスタマイズされたニーズに直面しています。その1つは、マーチャントAからの注文など、マーチャントごとに異なる支払い方法を表示することです。後払いの場合はAlipay、WeChat Pay、UnionPayが表示され、マーチャントBに注文した後の支払いの場合はAlipayとJDPayが表示されます。突然、メイトゥアンからメイトゥアンペイが出てきて、マーチャントBがメイトゥアンペイを受け入れた後、マーチャントBに食べ物を注文して支払うと、アリペイ、JDペイ、メイトゥアンペイが表示されました。このようなカスタマイズされたニーズはますます増えています。これらのSaaS製品にPaaSプラットフォームがない場合、さまざまなビジネスのニーズを満たすためにハードコードの条件を絶えず増やすことにうんざりします。これは明らかに持続可能な開発モデルではありません。

それでは、FCおよびサーバーレスワークフローを使用してこの問題をエレガントに解決する方法を見てみましょう。最初にこの注文プロセスを見てみましょう。

1.サーバーレスワークフローを介してプロセスを作成します

まず、上記のユーザー側のプロセスをプログラム側のプロセスに変換する必要があります。現時点では、サーバーレスワークフローを使用してこのタスクを実行する必要があります。

サーバーレスコンソールを開き、注文プロセスを作成します。ここで、サーバーレスワークフローは、プロセス定義言語FDLを使用してワークフローを作成します。FDLを使用してワークフローを作成する方法については、ドキュメントを参照してください。フローチャートを次の図に示します。

FDLコードは次のとおりです。

version: v1beta1
type: flow
timeoutSeconds: 3600
steps:
  - type: task
    name: generateInfo
    timeoutSeconds: 300
    resourceArn: acs:mns:::/topics/generateInfo-fnf-demo-jiyuan/messages
    pattern: waitForCallback
    inputMappings:
      - target: taskToken
        source: $context.task.token
      - target: products
        source: $input.products
      - target: supplier
        source: $input.supplier
      - target: address
        source: $input.address
      - target: orderNum
        source: $input.orderNum
      - target: type
        source: $context.step.name
    outputMappings:
      - target: paymentcombination
        source: $local.paymentcombination
      - target: orderNum
        source: $local.orderNum
    serviceParams:
      MessageBody: $
      Priority: 1
    catch:
      - errors:
          - FnF.TaskTimeout
        goto: orderCanceled
  -type: task
    name: payment
    timeoutSeconds: 300
    resourceArn: acs:mns:::/topics/payment-fnf-demo-jiyuan/messages
    pattern: waitForCallback
    inputMappings:
      - target: taskToken
        source: $context.task.token
      - target: orderNum
        source: $local.orderNum
      - target: paymentcombination
        source: $local.paymentcombination
      - target: type
        source: $context.step.name
    outputMappings:
      - target: paymentMethod
        source: $local.paymentMethod
      - target: orderNum
        source: $local.orderNum
      - target: price
        source: $local.price
      - target: taskToken
        source: $input.taskToken
    serviceParams:
      MessageBody: $
      Priority: 1
    catch:
      - errors:
          - FnF.TaskTimeout
        goto: orderCanceled
  - type: choice
    name: paymentCombination
    inputMappings:
      - target: orderNum
        source: $local.orderNum
      - target: paymentMethod
        source: $local.paymentMethod
      - target: price
        source: $local.price
      - target: taskToken
        source: $local.taskToken
    choices:
      - condition: $.paymentMethod == "zhifubao"
        steps:
          - type: task
            name: zhifubao
            resourceArn: acs:fc:cn-hangzhou:your_account_id:services/FNFDemo-jiyuan/functions/zhifubao-fnf-demo
            inputMappings:
              - target: price
                source: $input.price            
              - target: orderNum
                source: $input.orderNum
              - target: paymentMethod
                source: $input.paymentMethod
              - target: taskToken
                source: $input.taskToken
      - condition: $.paymentMethod == "weixin"
        steps:
          - type: task
            name: weixin
            resourceArn: acs:fc:cn-hangzhou:your_account_id:services/FNFDemo-jiyuan.LATEST/functions/weixin-fnf-demo
            inputMappings:
            - target: price
              source: $input.price            
            - target: orderNum
              source: $input.orderNum
            - target: paymentMethod
              source: $input.paymentMethod
            - target: taskToken
              source: $input.taskToken
      - condition: $.paymentMethod == "unionpay"
        steps:
          - type: task
            name: unionpay
            resourceArn: acs:fc:cn-hangzhou:your_account_id:services/FNFDemo-jiyuan.LATEST/functions/union-fnf-demo
            inputMappings:
            - target: price
              source: $input.price            
            - target: orderNum
              source: $input.orderNum
            - target: paymentMethod
              source: $input.paymentMethod
            - target: taskToken
              source: $input.taskToken
    default:
      goto: orderCanceled
  - type: task
    name: orderCompleted
    resourceArn: acs:fc:cn-hangzhou:your_account_id:services/FNFDemo-jiyuan.LATEST/functions/orderCompleted
    end: true
  - type: task
    name: orderCanceled
    resourceArn: acs:fc:cn-hangzhou:your_account_id:services/FNFDemo-jiyuan.LATEST/functions/cancerOrder

プロセス全体を分析する前に、サーバーレス関数の計算とサーバーレスワークフローによって順序付けモジュールを完全に構築するのではなく、柔軟性の問題を解決するためにのみ使用することを説明したいと思います。したがって、この例のメインアプリケーションはJavaで記述されています。 、次に、サーバーレス関数の計算とサーバーレスワークフローを組み合わせます。このプロセスを詳細に分析してみましょう。

2.起動プロセス

常識的には、注文を開始するとプロセスが開始されるはずなので、この例では、製品と販売者を選択し、住所を入力した後にプロセスを開始するように設計しています。

ここでは、サーバーレスワークフローによって提供されるOpenAPIを介してプロセスを開始します。

  • Java起動プロセス

この例では、サーバーレスワークフローのJava SDKを使用します。最初に、POMファイルに依存関係を追加します。

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>[4.3.2,5.0.0)</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-fnf</artifactId>
    <version>[1.0.0,5.0.0)</version>
</dependency>

次に、JavaSDKを初期化するConfigクラスを作成します。

@Configuration
public class FNFConfig {

    @Bean
    public IAcsClient createDefaultAcsClient(){
        DefaultProfile profile = DefaultProfile.getProfile(
                "cn-xxx",          // 地域ID
                "ak",      // RAM 账号的AccessKey ID
                "sk"); // RAM 账号Access Key Secret
        IAcsClient client = new DefaultAcsClient(profile);
        return client;
    }

}

コントローラのstartFNFメソッドを見てみましょう。このメソッドはGETインターフェイスを公開し、次の3つのパラメータを渡します。

  • fnfname:開始するプロセスの名前。
  • execuname:プロセスが開始された後のプロセスインスタンスの名前。
  • input:ビジネスパラメータなどの入力パラメータを開始します。
@GetMapping("/startFNF/{fnfname}/{execuname}/{input}")
    public StartExecutionResponse startFNF(@PathVariable("fnfname") String fnfName,
                                           @PathVariable("execuname") String execuName,
                                           @PathVariable("input") String inputStr) throws ClientException {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("fnfname", fnfName);
        jsonObject.put("execuname", execuName);
        jsonObject.put("input", inputStr);
        return fnfService.startFNF(jsonObject);
    }

ServiceのstartFNFメソッドを見てみましょう。このメソッドは2つの部分に分かれています。最初の部分は起動プロセスで、2番目の部分は注文オブジェクトを作成してストレージをシミュレートすることです(この例では、マップに配置されます)。

@Override
    public StartExecutionResponse startFNF(JSONObject jsonObject) throws ClientException {
        StartExecutionRequest request = new StartExecutionRequest();
        String orderNum = jsonObject.getString("execuname");
        request.setFlowName(jsonObject.getString("fnfname"));
        request.setExecutionName(orderNum);
        request.setInput(jsonObject.getString("input"));

        JSONObject inputObj = jsonObject.getJSONObject("input");
        Order order = new Order();
        order.setOrderNum(orderNum);
        order.setAddress(inputObj.getString("address"));
        order.setProducts(inputObj.getString("products"));
        order.setSupplier(inputObj.getString("supplier"));
        orderMap.put(orderNum, order);

        return iAcsClient.getAcsResponse(request);
    }

プロセスを開始するとき、プロセス名と開始プロセスインスタンスの名前は、渡す必要のあるパラメーターです。ここでは、開始プロセスのインスタンス名として毎回注文番号を使用します。入力に関しては、必要に応じてJSON文字列を作成できます。ここでは、製品、販売者、住所、注文番号のJSON文字列を作成し、プロセスの開始時にそれらをプロセスに渡します。

さらに、ウェアハウジングをシミュレートするために、この注文のOrderインスタンスが作成されてマップに保存されます。後続のリンクは、注文インスタンスにクエリを実行して注文属性を更新します。

  • VUE選択製品/販売者ページ

VUEを使用してフロントエンドを構築します。製品と販売者の選択ページで次のステップをクリックすると、GETを介してHTTPプロトコルインターフェイス/ startFNF / {fnfname} / {execuname} / {input}を呼び出します。上記のJavaメソッドに対応します。

  • fnfname:開始するプロセスの名前。
  • execuname:起動プロセスインスタンスの注文番号と名前としてuuidをランダムに生成します。
  • 入力:製品、販売者、注文番号、住所をJSON文字列として作成し、プロセスに渡します。
submitOrder(){
                const orderNum = uuid.v1()
                this.$axios.$get('/startFNF/OrderDemo-Jiyuan/'+orderNum+'/{\n' +
                    '  "products": "'+this.products+'",\n' +
                    '  "supplier": "'+this.supplier+'",\n' +
                    '  "orderNum": "'+orderNum+'",\n' +
                    '  "address": "'+this.address+'"\n' +
                    '}' ).then((response) => {
                    console.log(response)
                    if(response.message == "success"){
                        this.$router.push('/orderdemo/' + orderNum)
                    }
                })
            }

3.generateInfoノード

最初のノードgenerateInfo、FDLの意味を見てみましょう:

- type: task
    name: generateInfo
    timeoutSeconds: 300
    resourceArn: acs:mns:::/topics/generateInfo-fnf-demo-jiyuan/messages
    pattern: waitForCallback
    inputMappings:
      - target: taskToken
        source: $context.task.token
      - target: products
        source: $input.products
      - target: supplier
        source: $input.supplier
      - target: address
        source: $input.address
      - target: orderNum
        source: $input.orderNum
      - target: type
        source: $context.step.name
    outputMappings:
      - target: paymentcombination
        source: $local.paymentcombination
      - target: orderNum
        source: $local.orderNum
    serviceParams:
      MessageBody: $
      Priority: 1
    catch:
      - errors:
          - FnF.TaskTimeout
        goto: orderCanceled
```
  • name:ノード名。
  • timeoutSeconds:タイムアウト期間。このノードの待機時間は、時間が経過すると、gotoブランチが指すorderCanceledノードにジャンプします。
  • パターン:waitForCallbackに設定し、確認を待つ必要があることを示します。inputMappings:ノードはパラメーターを入力します。
  • taskToken:サーバーレスワークフローによって自動的に生成されるトークン。
  • 製品:選択された製品。
  • サプライヤー:選択された商人。
  • 住所:配送先住所。
  • orderNum:注文番号。
  • outputMappings:このノードの出力パラメーター。
  • Paymentcombination:販売者がサポートする支払い方法。
  • orderNum:注文番号。
  • catch:例外をキャッチし、他のブランチにジャンプします。

ここでは、resourceArnとserviceParamsを別々に説明する必要があります。サーバーレスワークフローは、複数のクラウドサービスとの統合をサポートします。つまり、他のサービスがタスクステップの実行単位として使用されます。サービス統合方法はFDL言語で表されます。タスクステップでは、resourceArnを使用して統合ターゲットサービスを定義し、patternを使用して統合モードを定義できます。したがって、acs:mns ::: / topics / generateInfo-fnf-demo-jiyuan / messages情報がresourceArnで構成されていることがわかります。つまり、MNSメッセージキューサービスがgenerateInfoノードに統合されています。generateInfoノードがトリガーされると、generateInfo-fnfに送信されます。 -demo-jiyuanTopicでメッセージを送信します。次に、メッセージ本文とパラメーターがserviceParamsオブジェクトで指定されます。MessageBodyはメッセージ本文であり、構成$は、メッセージ本文が入力マッピングinputMappingsによって生成されることを意味します。

最初のノードの例を読んだ後、サーバーレスワークフローでは、MNSを統合してメッセージを送信することにより、ノード間の情報転送を渡すことができます。これも、より広く使用されている方法の1つです。

4. generateInfo-fnf-demo関数

によってgenerateInfo-fnf-demo-jiyuanTopicに送信されるメッセージには、製品情報、ビジネス情報、住所、および注文プロセスの開始を示す注文番号が含まれています。メッセージがあるため、後続の処理のためにメッセージを受信します。したがって、関数コンピューティングコンソールを開き、サービスを作成し、サービスの下にgenerateInfo-fnf-demoという名前のイベントトリガー関数を作成します。ここで、[Pythonランタイム:

MNSトリガーを作成]を選択し、generateInfo-fnf-demo-jiyuanTopicの監視を選択します。

メッセージサービスMNSコンソールを開き、generateInfo-fnf-demo-jiyuanTopicを作成します。

関数を準備し、コードの記述を開始しましょう。

-- coding: utf-8 --
import logging
import json
import time
import requests
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkfnf.request.v20190315 import ReportTaskSucceededRequest
from aliyunsdkfnf.request.v20190315 import ReportTaskFailedRequest
def handler(event, context):

1.サーバーレスワークフロークライアントを構築する

region = "cn-hangzhou"
account_id = "XXXX"
ak_id = "XXX"
ak_secret = "XXX"
fnf_client = AcsClient(
    ak_id,
    ak_secret,
    region
)
logger = logging.getLogger()

2.イベントの情報を受け取ります

Topic generateInfo-fnf-demo-jiyuan中的消息内容,将其转换为Json对象
bodyJson = json.loads(event)
logger.info("products:" + bodyJson["products"])
logger.info("supplier:" + bodyJson["supplier"])
logger.info("address:" + bodyJson["address"])
logger.info("taskToken:" + bodyJson["taskToken"])
supplier = bodyJson["supplier"]
taskToken = bodyJson["taskToken"]
orderNum = bodyJson["orderNum"]

3.どの販売者がどの支払い方法の組み合わせを使用しているかを判断します

ここでの例は比較的単純で失礼です。通常の状況では、メタデータ構成メソッドを使用して以下を取得する必要があります。

paymentcombination = ""
if supplier == "haidilao":
    paymentcombination = "zhifubao,weixin"
else:
    paymentcombination = "zhifubao,weixin,unionpay"

4. Javaサービスによって公開されているインターフェイスを呼び出して、注文情報を更新します。主に支払い方法を更新します。

url = "http://xx.xx.xx.xx:8080/setPaymentCombination/" + orderNum + "/" + paymentcombination + "/0"
x = requests.get(url)

5. generateInfoノードに応答し、データを返します。データには、注文番号と支払い方法が返されます。

output = "{\"orderNum\": \"%s\", \"paymentcombination\":\"%s\" " \
                     "}" % (orderNum, paymentcombination)
request = ReportTaskSucceededRequest.ReportTaskSucceededRequest()
request.set_Output(output)
request.set_TaskToken(taskToken)
resp = fnf_client.do_action_with_exception(request)
return 'hello world'

generateInfo-fnf-demo関数はMNSトリガーで構成されているため、TopicgenerateInfo-fnf-demo-jiyuanにメッセージがあると、generateInfo-fnf-demo関数の実行がトリガーされます。

コード全体は5つの部分に分かれています。

  • サーバーレスワークフロークライアントを構築します。
  • イベントの情報は、TopicgenerateInfo-fnf-demo-jiyuanのメッセージコンテンツを受信し、それをJsonオブジェクトに変換します。
  • マーチャントが使用する支払い方法の組み合わせを決定するために、ここでの例は比較的単純で失礼です。通常の状況では、メタデータ構成を使用して取得する必要があります。たとえば、システムにはマーチャント情報の設定機能があります。マーチャントがインターフェイスでサポートする支払い方法を設定することにより、メタデータ設定情報が形成され、クエリインターフェイスが提供され、クエリがここで実行されます。
  • Javaサービスによって公開されているインターフェイスを呼び出して、注文情報を更新します。主に支払い方法を更新します。
  • generateInfoノードに応答を返し、注文番号と支払い方法が返されるデータを返します。このノードのパターンはwaitForCallbackであるため、応答結果を待つ必要があります。

5.支払いノード

2番目のノードの支払いを見てみましょう最初にFDLコードを見てください。

type: task
name: payment
timeoutSeconds: 300
resourceArn: acs:mns:::/topics/payment-fnf-demo-jiyuan/messages
pattern: waitForCallback
inputMappings:target: taskToken
source: $context.task.tokentarget: orderNum
source: $local.orderNum - target: paymentcombination source: $local.paymentcombinationtarget: type
source: $context.step.name outputMappings: - target: paymentMethod source: $local.paymentMethodtarget: orderNum
source: $local.orderNum - target: price source: $local.pricetarget: taskToken
source: $input.taskToken serviceParams: MessageBody: $
Priority: 1
catch:errors:FnF.TaskTimeout
goto: orderCanceled

プロセスフローが支払いノードに進むとき、それはユーザーが支払いページに入ったことを意味します。

このとき、支払いノードはMNSのTopicpayment-fnf-demo-jiyuanにメッセージを送信します。これにより、payment-fnf-demo機能がトリガーされます。

6.支払い-fnf-デモ機能

Payment-fnf-demo関数の作成方法は、generateInfo-fnf-demo関数に似ているため、ここでは冗長になりません。コードを直接見てみましょう。

# -*- coding: utf-8 -*-
import logging
import json
import os
import time
import logging
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkcore.client import AcsClient
from aliyunsdkfnf.request.v20190315 import ReportTaskSucceededRequest
from aliyunsdkfnf.request.v20190315 import ReportTaskFailedRequest
from mns.account import Account  # pip install aliyun-mns
from mns.queue import *

def handler(event, context):
    logger = logging.getLogger()
    region = "xxx"
    account_id = "xxx"
    ak_id = "xxx"
    ak_secret = "xxx"
    mns_endpoint = "http://your_account_id.mns.cn-hangzhou.aliyuncs.com/"
    queue_name = "payment-queue-fnf-demo"
    my_account = Account(mns_endpoint, ak_id, ak_secret)
    my_queue = my_account.get_queue(queue_name)
    # my_queue.set_encoding(False)
    fnf_client = AcsClient(
        ak_id,
        ak_secret,
        region
    )
    eventJson = json.loads(event)

    isLoop = True
    while isLoop:
        try:
            recv_msg = my_queue.receive_message(30)
            isLoop = False
            # body = json.loads(recv_msg.message_body)
            logger.info("recv_msg.message_body:======================" + recv_msg.message_body)
            msgJson = json.loads(recv_msg.message_body)
            my_queue.delete_message(recv_msg.receipt_handle)
            # orderCode = int(time.time())
            task_token = eventJson["taskToken"]
            orderNum = eventJson["orderNum"]
            output = "{\"orderNum\": \"%s\", \"paymentMethod\": \"%s\", \"price\": \"%s\" " \
                         "}" % (orderNum, msgJson["paymentMethod"], msgJson["price"])
            request = ReportTaskSucceededRequest.ReportTaskSucceededRequest()
            request.set_Output(output)
            request.set_TaskToken(task_token)
            resp = fnf_client.do_action_with_exception(request)
        except Exception as e:
            logger.info("new loop")
    return 'hello world'

この機能の中心的なアイデアは、ユーザーが支払い方法を選択して支払いページで支払いを確認するのを待つことです。したがって、MNSキューは待機をシミュレートするために使用されます。Payment-queue-fnf-demo内のメッセージがメッセージを受信するのを循環的に待ちます。メッセージが受信されると、注文番号と、ユーザーが選択した特定の支払い方法と金額が支払いノードに返されます。

7.VUE支払い方法の選択ページ

generateInfoノードの後、注文の支払い方法情報が利用可能であるため、ユーザーは、製品、販売者、住所を入力すると、ジャンプするページが確認支払いページになり、販売者のサポートが含まれます。支払方法。

ページに入ると、Javaサービスによって公開されているインターフェイスに注文情報を取得するように要求し、支払い方法に応じてページにさまざまな支払い方法を表示します。コードスニペットは次のとおりです。

ユーザーが支払い方法を選択して[注文の送信]ボタンをクリックすると、メッセージがpayment-queue-fnf-demoキューに送信されます。つまり、payment-fnf-demo関数に通知され、後続のロジックが続行されます。

ここでは、HTTPトリガータイプ関数を使用して、MNSにメッセージを送信するロジックを実装します。paymentMethod-fnf-demo関数コードは次のとおりです。

# -*- coding: utf-8 -*-

import logging
import urllib.parse
import json
from mns.account import Account  # pip install aliyun-mns
from mns.queue import *
HELLO_WORLD = b'Hello world!\n'

def handler(environ, start_response):
    logger = logging.getLogger() 
    context = environ['fc.context']
    request_uri = environ['fc.request_uri']
    for k, v in environ.items():
      if k.startswith('HTTP_'):
        # process custom request headers
        pass
    try:       
        request_body_size = int(environ.get('CONTENT_LENGTH', 0))   
    except (ValueError):       
        request_body_size = 0  
    request_body = environ['wsgi.input'].read(request_body_size) 
    paymentMethod = urllib.parse.unquote(request_body.decode("GBK"))
    logger.info(paymentMethod)
    paymentMethodJson = json.loads(paymentMethod)

    region = "cn-xxx"
    account_id = "xxx"
    ak_id = "xxx"
    ak_secret = "xxx"
    mns_endpoint = "http://your_account_id.mns.cn-hangzhou.aliyuncs.com/"
    queue_name = "payment-queue-fnf-demo"
    my_account = Account(mns_endpoint, ak_id, ak_secret)
    my_queue = my_account.get_queue(queue_name)
    output = "{\"paymentMethod\": \"%s\", \"price\":\"%s\" " \
                         "}" % (paymentMethodJson["paymentMethod"], paymentMethodJson["price"])
    msg = Message(output)
    my_queue.send_message(msg)

    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return [HELLO_WORLD]

この関数のロジックは非常に単純です。つまり、ユーザーが選択した支払い方法と金額をMNSキューpayment-queue-fnf-demoに送信します。
VUEコードスニペットは次のとおりです。

 

8.paymentCombinationノード

PaymentCombinationノードはルーティングノードであり、特定のパラメータを判断することでさまざまなノードにルーティングします。ここでは、当然、paymentMethodが判断条件として使用されます。FDLコードは次のとおりです。

- type: choice
    name: paymentCombination
    inputMappings:
      - target: orderNum
        source: $local.orderNum
      - target: paymentMethod
        source: $local.paymentMethod
      - target: price
        source: $local.price
      - target: taskToken
        source: $local.taskToken
    choices:
      - condition: $.paymentMethod == "zhifubao"
        steps:
          - type: task
            name: zhifubao
            resourceArn: acs:fc:cn-hangzhou:your_account_id:services/FNFDemo-jiyuan/functions/zhifubao-fnf-demo
            inputMappings:
              - target: price
                source: $input.price            
              - target: orderNum
                source: $input.orderNum
              - target: paymentMethod
                source: $input.paymentMethod
              - target: taskToken
                source: $input.taskToken
      - condition: $.paymentMethod == "weixin"
        steps:
          - type: task
            name: weixin
            resourceArn: acs:fc:cn-hangzhou:your_account_id:services/FNFDemo-jiyuan.LATEST/functions/weixin-fnf-demo
            inputMappings:
            - target: price
              source: $input.price            
            - target: orderNum
              source: $input.orderNum
            - target: paymentMethod
              source: $input.paymentMethod
            - target: taskToken
              source: $input.taskToken
      - condition: $.paymentMethod == "unionpay"
        steps:
          - type: task
            name: unionpay
            resourceArn: acs:fc:cn-hangzhou:your_account_id:services/FNFDemo-jiyuan.LATEST/functions/union-fnf-demo
            inputMappings:
            - target: price
              source: $input.price            
            - target: orderNum
              source: $input.orderNum
            - target: paymentMethod
              source: $input.paymentMethod
            - target: taskToken
              source: $input.taskToken
    default:
      goto: orderCanceled

ここでのプロセスは、ユーザーが支払い方法を選択した後、payment-fnf-demo関数にメッセージを送信し、次に支払い方法を返し、次にpaymentCombinationノードに流れて、支払いロジックを処理するノードと関数に流れる支払い方法を決定します。

9.zhifubaoノード

zhifubaoノードを具体的に見てみましょう。

choices:
      - condition: $.paymentMethod == "zhifubao"
        steps:
          - type: task
            name: zhifubao
            resourceArn: acs:fc:cn-hangzhou:your_account_id:services/FNFDemo-jiyuan/functions/zhifubao-fnf-demo
            inputMappings:
              - target: price
                source: $input.price            
              - target: orderNum
                source: $input.orderNum
              - target: paymentMethod
                source: $input.paymentMethod
              - target: taskToken
                source: $input.taskToken

このノードのresourceArnは、前の2つのノードとは異なります。関数計算の関数のARNはここで構成されます。つまり、プロセスフローがこのノードに移動すると、イベントによってトリガーされる関数であるzhifubao-fnf-demo関数がトリガーされます。ただし、トリガーを作成する必要はありません。このプロセスは、注文金額、注文番号、および支払い方法をzhifubao-fnf-demo関数に渡します。

10. zhifubao-fnf-demo 函数

次に、zhifubao-fnf-demo関数のコードを見てみましょう。

# -*- coding: utf-8 -*-
import logging
import json
import requests
import urllib.parse
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkfnf.request.v20190315 import ReportTaskSucceededRequest
from aliyunsdkfnf.request.v20190315 import ReportTaskFailedRequest

def handler(event, context):
  region = "cn-xxx"
  account_id = "xxx"
  ak_id = "xxx"
  ak_secret = "xxx"
  fnf_client = AcsClient(
    ak_id,
    ak_secret,
    region
  )
  logger = logging.getLogger()
  logger.info(event)
  bodyJson = json.loads(event)
  price = bodyJson["price"]
  taskToken = bodyJson["taskToken"]
  orderNum = bodyJson["orderNum"]
  paymentMethod = bodyJson["paymentMethod"]
  logger.info("price:" + price)
  newPrice = int(price) * 0.8
  logger.info("newPrice:" + str(newPrice))
  url = "http://xx.xx.xx.xx:8080/setPaymentCombination/" + orderNum + "/" + paymentMethod + "/" + str(newPrice)
  x = requests.get(url)

  return {"Status":"ok"}

この例のコードロジックは非常に単純です。金額を受け取った後、金額が20%割引され、価格が注文に更新されます。他の支払い方法のノードと機能は同じであり、実装ロジックを変更できます。この例では、WeChat Payには50%の割引があり、UnionPayには30%の割引があります。

11.プロセスを完了する

プロセス内のorderCompletedノードとorderCanceledノードにはロジックがなく、自分で使用できます。考え方は前のノードと同じです。したがって、完全なプロセスは次のようになります。

サーバーレスワークフローから見たノードフローは次のようになります。

総括する

この時点で、サーバーレスワークフローとサーバーレス関数の計算に基づいて作成された注文モジュールの例が完了しました。この例では、注意が必要な2つのポイントがあります。

  • 販売者と支払い方法のメタデータルールを構成します。
  • 支払いページのメタデータルールを確認します。

実際の制作では、カスタマイズ可能なパーツをメタデータの説明として抽象化し、販売者の支払い方法を定式化するための構成インターフェイス、つまりメタデータルールを更新する必要があるため、フロントエンドページにはメタデータ情報に基づいて対応するコンテンツが表示されます。

したがって、後で他の支払い方法にアクセスする必要がある場合は、paymentCombinationルーティングノードでルーティングルールを決定し、対応する支払い方法関数を追加するだけで済みます。メタデータ設定項目を追加することにより、新しく追加された支払い方法をページに表示し、新しい支払い方法を処理するための関数にルーティングすることができます。

 

著者|ジユアン

 

元のリンク

この記事はAlibabaCloudのオリジナルのコンテンツであり、許可なく複製することはできません。

おすすめ

転載: blog.csdn.net/weixin_43970890/article/details/112569927