• 如何针对 Python 运行时编写 Python 脚本
    • 函数名约定
    • 参数约定
    • Hello World!

    如何针对 Python 运行时编写 Python 脚本

    声明

    • 本文测试所用设备系统为 Ubuntu18.04
    • python 版本为 3.6,2.7 版本配置流程相同,但需要在 python 脚本中注意语言差异
    • 模拟 MQTT client 行为的客户端为 MQTTBox
    • 本文中基于 Hub 模块创建的服务名称为 localhub 服务。并且针对本文的测试案例中,对应的 localhub 服务、函数计算服务以及其他服务的配置统一如下:
    1. # 本地 Hub 配置
    2. # 配置文件位置: var/db/baetyl/localhub-conf/service.yml
    3. listen:
    4. - tcp://0.0.0.0:1883
    5. principals:
    6. - username: 'test'
    7. password: 'hahaha'
    8. permissions:
    9. - action: 'pub'
    10. permit: ['#']
    11. - action: 'sub'
    12. permit: ['#']
    13.  
    14. # 本地 baetyl-function-manager 配置
    15. # 配置文件位置: var/db/baetyl/function-manager-conf/service.yml
    16. hub:
    17. address: tcp://localhub:1883
    18. username: test
    19. password: hahaha
    20. rules:
    21. - clientid: localfunc-1
    22. subscribe:
    23. topic: py
    24. function:
    25. name: sayhi3
    26. publish:
    27. topic: py/hi
    28. functions:
    29. - name: sayhi3
    30. service: function-sayhi3
    31. instance:
    32. min: 0
    33. max: 10
    34. idletime: 1m
    35.  
    36. # python function 配置
    37. # 配置文件位置: var/db/baetyl/function-sayhi-conf/service.yml
    38. functions:
    39. - name: 'sayhi3'
    40. handler: 'sayhi.handler'
    41. codedir: 'var/db/baetyl/function-sayhi'
    42.  
    43. # application.yml配置
    44. # 配置文件位置: var/db/baetyl/application.yml
    45. version: v0
    46. services:
    47. - name: localhub
    48. image: hub.baidubce.com/baetyl/baetyl-hub
    49. replica: 1
    50. ports:
    51. - 1883:1883
    52. mounts:
    53. - name: localhub-conf
    54. path: etc/baetyl
    55. readonly: true
    56. - name: localhub-data
    57. path: var/db/baetyl/data
    58. - name: localhub-log
    59. path: var/log/baetyl
    60. - name: function-manager
    61. image: hub.baidubce.com/baetyl/baetyl-function-manager
    62. replica: 1
    63. mounts:
    64. - name: function-manager-conf
    65. path: etc/baetyl
    66. readonly: true
    67. - name: function-manager-log
    68. path: var/log/baetyl
    69. - name: function-sayhi3
    70. image: hub.baidubce.com/baetyl/baetyl-function-python36
    71. replica: 0
    72. mounts:
    73. - name: function-sayhi-conf
    74. path: etc/baetyl
    75. readonly: true
    76. - name: function-sayhi-code
    77. path: var/db/baetyl/function-sayhi
    78. readonly: true
    79. volumes:
    80. # hub
    81. - name: localhub-conf
    82. path: var/db/baetyl/localhub-conf
    83. - name: localhub-data
    84. path: var/db/baetyl/localhub-data
    85. - name: localhub-log
    86. path: var/db/baetyl/localhub-log
    87. # function manager
    88. - name: function-manager-conf
    89. path: var/db/baetyl/function-manager-conf
    90. - name: function-manager-log
    91. path: var/db/baetyl/function-manager-log
    92. # function python runtime sayhi
    93. - name: function-sayhi-conf
    94. path: var/db/baetyl/function-sayhi-conf
    95. - name: function-sayhi-code
    96. path: var/db/baetyl/function-sayhi-code

    Baetyl 官方提供了 Python 运行时,可以加载用户所编写的 Python 脚本。下文将针对 Python 脚本的名称,执行函数名称,输入,输出参数等内容分别进行说明。

    函数名约定

    Python 脚本的名称可以参照 Python 的通用命名规范,Baetyl 并未对此做特别限制。如果要应用某 Python 脚本对某条 MQTT 消息做处理,则相应的函数运行时服务的配置如下:

    1. functions:
    2. - name: 'sayhi3'
    3. handler: 'sayhi.handler'
    4. codedir: 'var/db/baetyl/function-sayhi'

    这里,我们关注 handler 这一属性,其中 sayhi 代表脚本名称,后面的 handler 代表该文件中被调用的入口函数。

    1. function-sayhi-code/
    2. ├── __init__.py
    3. └── sayhi.py

    更多函数运行时服务配置请查看 函数运行时服务配置释义。

    参数约定

    1. def handler(event, context):
    2. # do something
    3. return event

    Baetyl 官方提供的 Python 运行时支持 2 个参数: event 和 context,下面将分别介绍其用法。

    • event:根据 MQTT 报文中的 Payload 传入不同参数
      • 若原始 Payload 为一个 Json 数据,则传入经过 json.loads(Payload) 处理后的数据;
      • 若原始 Payload 为字节流、字符串(非 Json),则传入原 Payload 数据。
    • context:MQTT 消息上下文
      • context.messageQOS // MQTT QoS
      • context.messageTopic // MQTT Topic
      • context.functionName // MQTT functionName
      • context.functionInvokeID //MQTT function invokeID
      • context.invokeid // 同上,用于兼容 CFC提示:在云端 CFC 测试时,请注意不要直接使用 Baetyl 定义的上下文信息。推荐做法是先判断字段是否在 context 中存在,如果存在再读取。

    Hello World!

    下面我们实现一个简单的 Python 函数,目标是为每一条流经需要用该 Python 脚本进行处理的 MQTT 消息附加一条 hello world 信息。对于字典类消息,将其直接返回即可,对于非字典类消息,则将之转换为字符串后返回。

    1. #!/usr/bin/env python3
    2. # -*- coding: utf-8 -*-
    3.  
    4. def handler(event, context):
    5. result = {}
    6. if isinstance(event, dict):
    7. result['msg'] = event
    8. result['type'] = 'dict'
    9. result['say'] = 'hello world'
    10. else:
    11. result['msg'] = event.decode("utf-8")
    12. result['type'] = 'non-dict'
    13. result['say'] = 'hello world'
    14.  
    15. return result
    • 发送字典类数据:../_images/write-python-script-dict.png发送字典类数据

    • 发送非字典类数据:../_images/write-python-script-none-dict.png发送非字典类数据

    如上,对于一些常规的需求,我们通过系统 Python 环境的标准库就可以完成。但是,对于一些较为复杂的需求,往往需要引入第三方库来完成。如何解决这个问题?我们将在 如何针对 Python 运行时引入第三方包 小节详述。