编程知识 cdmana.com

Best practices of serverless in SaaS

brief introduction :  Especially for the current economic environment ,SaaS Manufacturers should understand , You can't burn money anymore , Just focus on your own number of users , And more to think about how to help customers reduce costs 、 Increase efficiency , So we need to put more energy on the customization ability of our products .
author : Alicloud Solution Architect Counting margin

With the Internet, the demographic dividend is weakening , Traffic based growth has slowed down , The Internet industry urgently needs to find a new blue ocean that can carry its own sustainable growth , Industrial Internet is the new trend under this grand background . We see the Internet wave sweeping traditional industries , Cloud computing 、 big data 、 AI began to integrate into finance on a large scale 、 manufacture 、 logistics 、 retail 、 recreational 、 education 、 In the production link of medical and other industries , This convergence is called the industrial Internet . And in the industrial Internet , One area that cannot be underestimated is SaaS field , It is ToB The backbone of the track , such as CRM、HRM、 Cost control system 、 Financial system 、 Collaborative office and so on .

SaaS System challenges
In the age of consumer Internet , People are searching for what they want , Various manufacturers in Cloud Computing 、 big data 、 Based on artificial intelligence and other technologies, the service and ecology with maximum flow are established , Based on massive content distribution and traffic sharing, the system is built logically . And in the era of industrial Internet , Supply relations have changed , You are customizing what you want , Two way construction should be carried out from both sides of supply and demand , At this time, the flexibility and scalability of the system are facing unprecedented challenges , In especial ToB Of SaaS field .

Especially for the current economic environment ,SaaS Manufacturers should understand , You can't burn money anymore , Just focus on your own number of users , And more to think about how to help customers reduce costs 、 Increase efficiency , So we need to put more energy on the customization ability of our products .

How to deal with challenges
SaaS The best in the field Salesforce, take CRM The concept of Marketing、Sales、Service, Of these three areas, only Sales Specialized SaaS product , The other two areas are different ISV Industry solutions in different industries , By what ? Beyond all doubt , yes Salesforce Powerful aPaaS platform .ISV、 Internal implementation 、 Customers can pass the aPaaS Platform to build their own industry 、 In your field SaaS System , Establish a complete ecology . So in my opinion , current Salesforce Has been established by a SaaS The company is sublimated into one aPaaS Platform company . This evolution process also confirms the transformation logic of consumer Internet and industrial Internet, as well as the core demands of the latter .

But not all SaaS Companies have the money and time to incubate and polish their own aPaaS platform , But changes in the market 、 The demands of users are real . To survive , We need to change . The core of this change is to be able to make your current SaaS The system became flexible , Relatively difficult to build aPaaS platform , We can actually choose lightweight and effective ones Serverless Solutions to enhance the flexibility and scalability of existing systems , In order to achieve different customization needs of users .

Serverless workflow
In the last article 《 Resource cost double optimization ! see Serverless Innovative practice of subverting Programming Education 》 in , Have been to Serverless I have explained the concept of , And also introduced Serverless Function calculation (FC) The concept and practice of . This article introduces the core elements of building system flexibility service choreography ——Serverless workflow .

Serverless Workflow is a fully managed cloud service used to coordinate the execution of multiple distributed tasks . stay Serverless In workflow , You can use order 、 Branch 、 To arrange distributed tasks in parallel ,Serverless The workflow reliably coordinates task execution according to the set steps , Track state transitions for each task , And execute your defined retry logic if necessary , To ensure that the workflow is completed .Serverless Workflow monitors workflow execution by providing logging and auditing , You can easily diagnose and debug applications .

The picture below describes Serverless How workflow coordinates distributed tasks , These tasks can be functions 、 Integrated cloud services API、 A program running on a virtual machine or container .

After watching Serverless Introduction of Workflow , You may have some ideas . The core of system flexibility and scalability is service choreography , No matter it was before BPM Or now aPaaS. So based on the Serverless Workflow refactoring SaaS The core idea of system flexibility scheme , It is to sort out the functions that users most want to customize in the system 、 Split 、 Pull away , Coordination function calculation (FC) Provide stateless capabilities , adopt Serverless The workflow arranges these function points , So as to achieve different business processes .

Calculate by function FC and Serverless Flexible ordering module based on Workflow
I believe we are not unfamiliar with the scene of ordering , Order takeout at home or order at a restaurant , It's all about this scene . At present, there are also many systems providing ordering SaaS Service provider , There are many good ones SaaS Ordering system . With the transformation of consumer Internet to industrial Internet , these SaaS The ordering system is facing more and more customized demands , One of the requirements is that different businesses will show different payment methods when paying , For instance from A Alipay will be shown after payment. 、 Wechat payment 、 UnionPay payment , from B Alipay will be shown after payment. 、 Jingdong payment . All of a sudden, meituan came out again and paid by meituan , here B Merchant receives meituan payment , So from B Alipay will be shown after payment. 、 Jingdong payment 、 Meituan payment . There is a growing demand for customization , these SaaS Product if not PaaS platform , Then you will be tired of constantly adding condition judgment through hard code to meet the needs of different businesses , This is obviously not a sustainable development model .

So let's take a look at functional computation FC and Serverless How can workflow solve this problem gracefully . Let's take a look at the ordering process :

adopt Serverless Workflow creation process
First of all, I need to convert the user side process above to the program side process , You need to use Serverless Workflow to take on this task .
open Serverless Console , Create ordering process , here Serverless Workflow uses process definition language FDL Create workflow , How to use FDL Please refer to the document for creating workflow . The flow chart is shown in the figure below :

FDL The code is :

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
    Before parsing the entire process , The first thing I want to make clear is that , We didn't pass it completely Serverless Function calculation and Serverless Workflow to build the ordering module , Just use it to solve the problem of flexibility , So the main application of this example is Java Compiling , And then combined Serverless Function calculation and Serverless workflow . Now let's analyze this process in detail .

Start process
As a rule , When you start ordering, the process should start , So in this example , My design is when we've finished choosing products and businesses 、 Start the process after filling in the address :

Here we go through Serverless Workflow provides OpenAPI To start the process .

Java Start process
I use this example Serverless Workflow Java SDK, First, in the POM Add dependencies to the file :

com.aliyun aliyun-java-sdk-core [4.3.2,5.0.0) com.aliyun aliyun-java-sdk-fnf [1.0.0,5.0.0) Then create the initialization Java SDK Of Config class :

@Configuration
public class FNFConfig {

@Bean
public IAcsClient createDefaultAcsClient(){
    DefaultProfile profile = DefaultProfile.getProfile(
            "cn-xxx",          //  regional ID
            "ak",      // RAM  Account number AccessKey ID
            "sk"); // RAM  account number Access Key Secret
    IAcsClient client = new DefaultAcsClient(profile);
    return client;
}

}
Look again. Controller Medium startFNF Method , This method is exposed GET The interface of the way , Pass in three parameters :

fnfname: The name of the process to start .
execuname: The name of the process instance after the process is started .
input: Start input parameters , For example, business parameters .
@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);
}
Look again. Service Medium startFNF Method , The method is divided into two parts , The first part is to start the process , The second part is to create the order object , And simulate the storage ( In the example, the Map In the ):

@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);
}

When starting the process , The process name and the name of the start process instance are the parameters that need to be passed in , Here I use the order number of each time as the instance name of the start process . as for Input, It can be constructed according to requirements JSON String input . Here I will merchandise 、 merchants 、 Address 、 The order number is constructed JSON The string is passed into the process when the process starts .

in addition , Created the Order example , And exist Map in , Simulated stock in , In subsequent phases, the order instance will be queried to update the order properties .

VUE Choose products / Merchant page
Front end I use VUE build , When you click the next step on the select products and merchants page , adopt GET Way to call HTTP Interface to protocol /startFNF/{fnfname}/{execuname}/{input}. And the above Java Methods corresponding to the .

fnfname: The name of the process to start .
execuname: Random generation uuid, As the number of the order , Also as the name of the initiating process instance .
input: Put the goods 、 merchants 、 The order number 、 Address constructed as JSON String transfer process .
submitOrder(){
const orderNum = uuid.v1()
this. a x i o s . axios. 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)
}
})
}
generateInfo node
First node generateInfo, First look at it. FDL The meaning of :

  • 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: The name of the node .
        timeoutSeconds: Timeout time . The length of time that the node waits , It will jump to the goto Branch directed orderCanceled node .
        pattern: Set to waitForCallback, Indicates that you need to wait for confirmation .inputMappings: This node is a parameter .
        taskToken:Serverless Workflow automatically generated Token.
        products: Selected products .
        supplier: Selected businesses .
        address: Delivery address .
        orderNum: The order number .
        outputMappings: The output parameter of the node .
        paymentcombination: Payment method supported by the merchant .
        orderNum: The order number .
        catch: Capture exception , Jump to other branches .
        here resourceArn and serviceParams It needs to be explained separately .Serverless Workflow supports integration with multiple cloud services , Other services are used as execution units of task steps . Service integration mode is provided by FDL Language expression , In the task step , have access to resourceArn To define the target services for integration , Use pattern Defining integration patterns . So you can see in resourceArn Middle configuration acs:mns:::/topics/generateInfo-fnf-demo-jiyuan/messages Information , That is to say generateInfo Integrated in the node MNS Message Queuing service , When generateInfo When the node is triggered, the generateInfo-fnf-demo-jiyuanTopic Send a message in . The message body and parameters are displayed in the serviceParams Object .MessageBody Is the message body , To configure $ Represents mapping through input inputMappings Generate message body .

Look at the example of the first node , You can see , stay Serverless In workflow , Information transfer between nodes can be realized through integration MNS Send a message to deliver , It is also one of the more widely used ways .

generateInfo-fnf-demo function
towards generateInfo-fnf-demo-jiyuanTopic The message sent in contains product information 、 Merchant information 、 Address 、 The order number , Indicates the beginning of an order placing process , Since there is a message , Then, there must be a receiving message for subsequent processing . So open the function calculation console , Create services , Create a service named generateInfo-fnf-demo Event trigger function for , Choose here Python Runtime:

establish MNS trigger , Choose monitor generateInfo-fnf-demo-jiyuanTopic.

Open message service MNS Console , establish generateInfo-fnf-demo-jiyuanTopic:

Prepare functions well , Let's start writing code :

-- 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. structure Serverless workflow Client
region = “cn-hangzhou”
account_id = “XXXX”
ak_id = “XXX”
ak_secret = “XXX”
fnf_client = AcsClient(
ak_id,
ak_secret,
region
)
logger = logging.getLogger()
# 2. event The information in the database is received Topic generateInfo-fnf-demo-jiyuan Message content in , Convert it to Json object
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. Determine which businesses use what payment combination , The example here is simple , Under normal circumstances , It should be obtained by metadata configuration
paymentcombination = “”
if supplier == “haidilao”:
paymentcombination = “zhifubao,weixin”
else:
paymentcombination = “zhifubao,weixin,unionpay”

# 4.  call Java Service exposed interface , Update order information , Mainly to update the payment method 
url = "http://xx.xx.xx.xx:8080/setPaymentCombination/" + orderNum + "/" + paymentcombination + "/0"
x = requests.get(url)

# 5.  To give generateInfo Node response , And return the data , The order number and payment method are returned here 
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'

because generateInfo-fnf-demo Function is configured MNS trigger , So when TopicgenerateInfo-fnf-demo-jiyuan Execution is triggered when there is a message generateInfo-fnf-demo function .

The whole code is divided into five parts :

structure Serverless workflow Client.
event The information in the database is received TopicgenerateInfo-fnf-demo-jiyuan Message content in , Convert it to Json object .
Determine which businesses use what payment combination , The example here is simple , Under normal circumstances , It should be obtained by metadata configuration . For example, there is the configuration function of business information in the system , By configuring which payment methods the merchant supports on the interface , Form metadata configuration information , Provide query interface , Query here .
call Java Service exposed interface , Update order information , Mainly to update the payment method .
To give generateInfo Node response , And return the data , The order number and payment method are returned here . Because of the pattern yes waitForCallback, So you need to wait for the response .
payment node
Let's look at the second node payment, First look FDL Code :

  • 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
    When the process flows to payment After node , It means that the user enters the payment page .

At this time payment The node will MNS Of Topicpayment-fnf-demo-jiyuan Send a message , Will trigger payment-fnf-demo function .

payment-fnf-demo function
payment-fnf-demo Function creation and generateInfo-fnf-demo Function similar to , There's no more encumbrance here . Let's go straight to the code :

-- 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'

The core idea of this function is to wait for the user to select a payment method on the payment page to confirm the payment . So it's used here MNS To simulate waiting . Loop wait for receive queue payment-queue-fnf-demo The messages in the , After receiving the message, return the order number and the specific payment method and amount selected by the user to payment node .

VUE Select payment method page
Because after generateInfo After node , The payment method information for this order is available , So for users , When the item is completed 、 merchants 、 After the address , The page you jump to is the confirmation payment page , It also includes the payment methods supported by the merchant .

After entering the page , Will ask Java Service exposed interface , Get order information , Different payment methods are displayed on the page according to the payment method . The code snippet is as follows :

When the user selects a payment method and clicks the submit order button , towards payment-queue-fnf-demo Queue to send messages , Notice payment-fnf-demo The function continues the subsequent logic .

Here I use a HTTP Function of trigger type , To implement MNS The logic of sending messages ,paymentMethod-fnf-demo The function code is as follows .

-- 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]

The logic of this function is simple , That is to say MNS Queues payment-queue-fnf-demo Send the payment method and amount selected by the user .
VUE The code snippet is as follows :

paymentCombination node
paymentCombination A node is a routing node , By judging a parameter to route to different nodes , It's natural to use here paymentMethod As a condition of judgment .FDL The code is as follows :

  • 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
    The process here is , After the user chooses the payment method , Send by message to payment-fnf-demo function , The payment method is then returned , So it was transferred to paymentCombination The node flows to the node and function that processes the payment logic by judging the payment method .

zhifubao node
Let's take a concrete look at one zhifubao node :

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

Of this node resourceArn Different from the previous two nodes , The configuration here is for the function in function calculation ARN, That is to say, when the process flows to this node, it will trigger zhifubao-fnf-demo function , This function is an event trigger function , But you don't need to create any triggers . The process changes the order amount 、 The order number 、 Payment method passed to zhifubao-fnf-demo function .

zhifubao-fnf-demo function
Now let's look at zhifubao-fnf-demo Function code :

-- 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”}
The code logic in the example is simple , After receiving the amount , Mark the amount 8 fold , The price is then updated back to the order . The nodes and functions of other payment methods are as follows , Change the implementation logic . In this example , Wechat payment 5 fold , UnionPay payment 7 fold .

Complete process
In the process orderCompleted and orderCanceled Nodes don't do much logic , You can play by yourself , The idea is the same as the previous node . So the whole process is like this :

from Serverless The flow of nodes seen in the workflow is like this :

summary
Here we are , We are based on Serverless Workflow and Serverless The order module example built by function calculation is completed , In the example , There are two points that need your attention :

Metadata rules for configuring merchants and payment methods .
Confirm metadata rules of payment page .
Because in actual production , We need to abstract the customizable parts as metadata descriptions , It is necessary to have a configuration interface to formulate the payment method of merchants, that is, to update metadata rules , Then the front page displays the corresponding content based on the metadata information .

So if you need to access other payment methods later , Just in paymentCombination Determine the routing rules in the routing node , Then add the corresponding payment method function . Configure items by adding metadata , The new payment method can be displayed on the page , And route to the function that processes the new payment method .

The above content serves as a stone to throw a brick to attract jade , Explore Serverless Application scenarios of , To solve SaaS The pain points of flexibility and expansibility of manufacturers . If you have any questions, you can also join the nail group 35712134 To find out , We will not see each other !

Link to the original text
This article is the original content of Alibaba cloud , No reprint without permission .

版权声明
本文为[Aliyun yunqi]所创,转载请带上原文链接,感谢
https://cdmana.com/2020/12/20201224224302731i.html

Scroll to Top