华为云用户手册

  • Java的initializer入口介绍 函数工作流 服务目前支持以下Java运行环境。 Java 8 (runtime = Java8) Java 11(runtime = Java11) Java 17(runtime = Java17) Initializer格式为:[包名].[类名].[执行函数名] 示例:创建函数时指定的initializer为com.huawei.Demo.my_initializer,那么FunctionGraph会去加载com.huawei包,Demo类中定义的my_initializer函数。 在函数工作流服务中使用Java实现initializer接口,需要定义一个java函数作为initializer入口,以下为initializer的简单示例。 public void my_initializer(Context context) { RuntimeLogger log = context.getLogger(); log.log(String.format("ak:%s", context.getAccessKey())); } 函数名 my_initializer需要与实现initializer接口时的initializer字段相对应。 context参数 context参数中包含一些函数的运行时信息,例如:request id、临时AccessKey、function meta等。
  • 示例事件 SMN 示例事件 { "record": [ { "event_version": "1.0", "smn": { "topic_urn": "urn:smn:{region}:0162c0f220284698b77a3d264376343a:{function_name}", "timestamp": "2018-01-09T07:11:40Z", "message_attributes": null, "message": "this is smn message content", "type": "notification", "message_id": "a51671f77d4a479cacb09e2cd591a983", "subject": "this is smn message subject" }, "event_subscription_urn": "urn:fss:{region}:0162c0f220284698b77a3d264376343a:function:default:read-smn-message:latest", "event_source": "smn" } ], "functionname": "test", "requestId": "7c307f6a-cf68-4e65-8be0-4c77405a1b2c", "timestamp": "Wed Nov 15 2017 12:00:00 GMT+0800 ( CS T)" } 表1 参数说明 参数 类型 示例值 描述 event_version String 1.0 事件协议的版本。 topic_urn String 参考示例 SMN事件唯一编号 type String notification 事件的类型 RequestID String 7c307f6a-cf68-4e65-8be0-4c77405a1b2c 请求ID。每个请求的ID取值唯一。 message_id String a51671f77d4a479cacb09e2cd591a983 消息ID。每条消息的ID取值唯一。 Message String this is smn message content 消息内容 event_source String smn 事件源 event_subscription_urn String 参考示例 添加的订阅唯一编号 timestamp String Wed Nov 15 2017 12:00:00 GMT+0800 (CST) 事件发生的时间 APIG示例事件 { "body": "{\"test\":\"body\"}", "requestContext": { "apiId": "bc1dcffd-aa35-474d-897c-d53425a4c08e", "requestId": "11cdcdcf33949dc6d722640a13091c77", "stage": "RELEASE" }, "queryStringParameters": { "responseType": "html" }, "httpMethod": "GET", "pathParameters": { "path":"value" }, "headers": { "accept-language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "accept-encoding": "gzip, deflate, br", "x-forwarded-port": "443", "x-forwarded-for": "103.218.216.98", "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "upgrade-insecure-requests": "1", "host": "50eedf92-c9ad-4ac0-827e-d7c11415d4f1.apigw.region.cloud.com", "x-forwarded-proto": "https", "pragma": "no-cache", "cache-control": "no-cache", "x-real-ip": "103.218.216.98", "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0" }, "path": "/apig-event-template", "isBase64Encoded": true } 约束与限制: 通过APIG服务调用函数服务时,isBase64Encoded的值默认为true,表示APIG传递给FunctionGraph的请求体body已经进行Base64编码,需要先对body内容Base64解码后再处理。 函数必须按以下结构返回字符串。 { "isBase64Encoded": true|false, "statusCode": httpStatusCode, "headers": {"headerName":"headerValue",...}, "body": "..." } 表2 参数说明 参数 类型 示例值 描述 body String "{\"test\":\"body\"}" 记录实际请求转换为String字符串后的内容。 requestContext Map 参考示例 请求来源的API网关的配置信息、请求标识、认证信息、来源信息。 httpMethod String GET 记录实际请求的HTTP方法 queryStringParameters Map 参考示例 记录在API网关中配置过的Query参数以及实际取值。 pathParameters Map 参考示例 记录在API网关中配置过的Path参数以及实际取值。 headers Map 参考示例 记录实际请求的完整Header内容 path String /apig-event-template 记录实际请求的完整的Path信息 isBase64Encoded Boolean True 默认为true DIS示例事件 { "ShardID": "shardId-0000000000", "Message": { "next_partition_cursor": "eyJnZXRJdGVyYXRvclBhcmFtIjp7InN0cmVhbS1uYW1lIjoiZGlzLXN3dGVzdCIsInBhcnRpdGlvbi1pZCI6InNoYXJkSWQtMDAwMDAwMDAwMCIsImN1cnNvci10eXBlIjoiVFJJTV9IT1JJWk9OIiwic3RhcnRpbmctc2VxdWVuY2UtbnVtYmVyIjoiNCJ9LCJnZW5lcmF0ZVRpbWVzdGFtcCI6MTUwOTYwNjM5MjE5MX0", "records": [ { "partition_key": "shardId_0000000000", "data": "d2VsY29tZQ==", "sequence_number": "0" }, { "partition_key": "shardId_0000000000", "data": "dXNpbmc=", "sequence_number": "1" }, { "partition_key": "shardId_0000000000", "data": "RnVuY3Rpb25TdGFnZQ==", "sequence_number": "2" }, { "partition_key": "shardId_0000000000", "data": "c2VydmljZQ==", "sequence_number": "3" } ], "millis_behind_latest": "" }, "Tag": "latest", "StreamName": "dis-swtest" } 表3 参数说明 参数 类型 示例值 描述 ShardID String shardId-0000000000 数据下载分区的ID next_partition_cursor String 参考示例 下一个分区的游标 Records Map 参考示例 存储在DIS通道中的数据单元 partition_key String 参考示例 分区键 data String 参考示例 数据块,由数据生产者添加到数据通道 sequence_number Int 参考示例 每个记录的唯一标识符,由DIS服务自动分配 Tag String latest 通道的标签 StreamName String dis-swtest 通道名称 TIMER示例事件 { "version": "v1.0", "time": "2018-06-01T08:30:00+08:00", "trigger_type": "TIMER", "trigger_name": "Timer_001", "user_event": "User Event" } 表4 参数说明 参数 类型 示例值 描述 version String V1.0 事件协议的版本 time String 2018-06-01T08:30:00+08:00 事件产生的时间 trigger_type String TIMER 触发器的类型 trigger_name String Timer_001 触发器的名字 user_event String User Event 在创建触发器时配置的附加信息 LTS示例事件 { "lts": { "data": "ICB7CiAgICAibG9ncyI6W3sKICAgICAgICAgIm1lc3NhZ2UiOiIyMDE4LTA4LTA4LzA4OjA4OjA4IFtXUk5dIFt0ZXN0LmdvOjA4XVRoaXMgaXMgYSB0ZXN0IG1lc3NhZ2UuIiwKICAgICAgICAgInRpbWUiOjE1MzAwMDk2NTMwNTksCiAgICAgICAgICJob3N0X25hbWUiOiJlY3MtdGVzdCIsCiAgICAgICAgICJpcCI6IjE5Mi4xNjguMS4xIiwKICAgICAgICAgInBhdGgiOiJ2YXIvbG9nL3Rlc3QubG9nIiwKICAgICAgICAgImxvZ191aWQiOiI2NjNkNjkzMC03OTJkLTExZTgtOGIwOC0yODZlZDQ4OGNlNzAiLAogICAgICAgICAibGluZV9ubyI6MQogICAgIH1dLAogICAgIm93bmVyIjogIjYyODBlMTcwYmQ5MzRmNjBhNGQ4NTFjZjVjYTA1MTI5IiwKICAgICJsb2dfZ3JvdXBfaWQiOiAiOTdhOWQyODQtNDQ0OC0xMWU4LThmYTQtMjg2ZWQ0ODhjZTcwIiwKICAgICJsb2dfdG9waWNfaWQiOiAiMWE5Njc1YTctNzg0ZC0xMWU4LTlmNzAtMjg2ZWQ0ODhjZTcwIgogfQ==" } } 表5 Event中涉及的参数解释 参数 类型 示例值 描述 data Sting 参考示例 Base64编码后的数据 CTS 示例事件 { "cts": { "time": "2018/06/26 08:54:07 GMT+08:00", "user": { "name": "userName", "id": "5b726c4fbfd84821ba866bafaaf56aax", "domain": { "name": "domainName", "id": "b2b3853af40448fcb9e40dxj89505ba" } }, "request": {}, "response": {}, "code": 204, "service_type": "vpc", "resource_type": "VPC", "resource_name": "workflow-2be1", "resource_id": "urn:fgs:{region}:2d1d891d93054bbaa69b9e866c0971ac:graph:workflow-2be1", "trace_name": "deleteGraph", "trace_type": "ConsoleAction", "record_time": "2018/06/26 08:54:07 GMT+08:00", "trace_id": "69be64a7-0233-11e8-82e4-e5d37911193e", "trace_status": "normal" } } 表6 参数说明 参数 类型 示例值 描述 User Map 参考示例 本次请求的发起用户信息 Request Map 参考示例 事件请求内容 Response Map 参考示例 事件响应内容 Code Int 204 事件响应码,例如200、400 service_type String vpc 发送方的简写,比如vpc,ecs等等 resource_type String VPC 发送方资源类型,比如vm,vpn等等 resource_name String workflow-2be1 资源名称,例如ecs服务中某个虚拟机的名称 trace_name String deleteGraph 事件名称,比如:startServer, shutDown等 trace_type String ConsoleAction 事件发生源头类型,例如ApiCall record_time string 2018/06/26 08:54:07 GMT+08:00 cts服务接受到这条trace的时间 trace_id String 69be64a7-0233-11e8-82e4-e5d37911193e 事件的唯一标识符 trace_status String normal 事件的状态 DDS示例事件 { "records": [ { "event_source": "dds", "event_name": "insert", "region": "{region}", "event_version": "1.0", "dds": { "size_bytes": "100", "token": "{\"_data\": \"825D8C2F4D0000001529295A100474039A3412A64BA89041DC952357FB4446645F696400645D8C2F8E5BECCB6CF5370D6A0004\"}", "full_document": "{\"_id\": {\"$oid\": \"5d8c2f8e5beccb6cf5370d6a\"},\"name\": \"dds\",\"age\": {\"$numberDouble\": \"52.0\"}}", "ns": "{\"db\": \"functiongraph\",\"coll\": \"person\"}" }, "event_source_id": "e6065860-f7b8-4cca-80bd-24ef2a3bb748" } ] } 表7 参数说明 参数 类型 示例值 描述 region String cn-north-1 DDS实例所在的地域 event_version String 1.0 事件协议的版本 event_source String dds 事件的来源 event_name String insert 事件的名字 size_bytes Int 100 消息的字节数 token String 参考示例 Base64编码后的数据 full_document String 参考示例 完整的文件信息 ns String 参考示例 列名 event_source_id e6065860-f7b8-4cca-80bd-24ef2a3bb748 参考示例 事件源唯一标识符 Kafka示例事件 { "event_version": "v1.0", "event_time": 1576737962, "trigger_type": "KAFKA", "region": "{region}", "instance_id": "81335d56-b9fe-4679-ba95-7030949cc76b", "records": [ { "messages": [ "kafka message1", "kafka message2", "kafka message3", "kafka message4", "kafka message5" ], "topic_id": "topic-test" } ] } 表8 参数说明 参数 类型 示例值 描述 event_version String v1.0 事件协议的版本 event_time String 2018-01-09T07:50:50.028Z 事件发生的时间 trigger_type String KAFKA 事件类型 region String cn-north-1 Kafka实例所在的地域 instance_id String 81335d56-b9fe-4679-ba95-7030949cc76b 创建的Kafka实例的唯一标识符。 messages String 参考示例 消息内容 topic_id String topic-test 消息的唯一标识符 GeminiDB示例事件 { "records": [ { "event_name": "\"insert\"", "event_version": "1.0", "event_source": "gemini_mongo", "region": "{region}", "gemini_mongo": { "full_document": "{\"_id\": {\"$oid\":\"5f61de944778db5fcded3f87\"},\"zhangsan\": \"zhangsan\"}", "ns": "{\"db\": \"zhangsan\",\"coll\": \"zhangsan\"}", "size_bytes": "100", "token": "{\"_data\": \"825F61DE940000000129295A1004A2D9AE61206C43A5AF47CAF7C5C00C5946645F696400645F61DE944778DB5FCDED3F870004\"}" }, "event_source_id": "51153d19-2b7d-402c-9a79-757163258a36" } ], "vernier": "{\"_data\": \"825F61DE940000000129295A1004A2D9AE61206C43A5AF47CAF7C5C00C5946645F696400645F61DE944778DB5FCDED3F870004\"}" } 表9 参数说明 参数 类型 示例值 描述 region String cn-north-1 GeminiDB实例所在的地域 event_source String gemini_mongo 事件的来源 event_version String 1.0 事件协议的版本 full_document String 参考示例 完整的文件信息 size_bytes Int 100 消息的字节数 token String 参考示例 Base64编码后的数据 vernier String 参考示例 游标 RabbitMQ示例事件 { "event_version": "v1.0", "event_time": 1576737962, "trigger_type": "RABBITMQ", "region": "{region}", "records": [ { "messages": [ "rabbitmq message1", "rabbitmq message2", "rabbitmq message3", "rabbitmq message4", "rabbitmq message5" ], "instance_id": "81335d56-b9fe-4679-ba95-7030949cc76b", "exchange": "exchange-test" } ] } 表10 参数说明 参数 类型 示例值 描述 event_version String v1.0 事件协议的版本 Region String cn-north-1 RabbitMQ实例所在的地域 instance_id String 81335d56-b9fe-4679-ba95-7030949cc76b 创建的RabbitMQ实例的唯一标识符。 EG示例事件 RocketMQ自定义事件源 { "datacontenttype": "application/json", "data": { "context": "yyyyy" }, "subject": "ROCKETMQ:region:domainId/projectId:ROCKETMQ:eventSourceName", "specversion": "1.0", "id": "016d5bd3-6231-4e9e-86ef-e451a070d598", "source": "eventSourceName", "time": "2023-04-07T11:51:10Z", "type": "ROCKETMQ:CloudTrace:RocketmqCall" } OBS应用事件源 { "channel_id":"b65779ed-d9d0-4a6c-b312-c767226964cf", "description":"", "name":"subscription-xeak", "sources":[ { "id":null, "name":"HC.OBS.DWR", "detail":{ "bucket":"eventbucket", "objectKeyEncode":true }, "filter":{ "source":[ { "op":"StringIn", "values":[ "HC.OBS.DWR" ] } ], "type":[ { "op":"StringIn", "values":[ "OBS:DWR:ObjectCreated:PUT", "OBS:DWR:ObjectCreated:POST" ] } ], "subject":{ "and":[ { "op":"StringStartsWith", "values":[ "/ddd" ] } ] }, "data":{ "obs":{ "bucket":{ "name":[ { "op":"StringIn", "values":[ "output-your" ] } ] } } } }, "provider_type":"OFFICIAL" } ], "targets":[ { "id":null, "name":"HC.FunctionGraph", "detail":{ "urn":"urn:fss:cn-north-7:c53626012ba84727b938ca8bf03108ef:function:A-nodejs-lqz:pylog:latest", "agency_name":"EG_AGENCY" }, "dead_letter_queue":null, "provider_type":"OFFICIAL", "transform":{ "type":"ORIGINAL", "value":"" } } ] } 云服务事件源: { "specversion":"1.0", "id":"eaf3b6a6-d525-11ed-a4ca-1baaeb906770", "source":"HC.OBS", "type":"OBS:CloudTrace:Others", "datacontenttype":"application/json", "subject":"OBS:cn-north-5:1d60cc02b9814b9e8cab1ff36886cacb/a5b94f2084a14e3eb8273dd224b89d9a:OBJECT", "time":"2023-04-07T09:21:53.271Z", "data":{ "code":"200", "source_ip":"10.62.9.176", "trace_type":"Others", "event_type":"data", "project_id":"a5b94f2084a14e3eb8273dd224b89d9a", "total_time":"138", "content_length":"6887848", "trace_id":"eaf3b6a6-d525-11ed-a4ca-1baaeb906770", "trace_name":"GET.OBJECT", "resource_type":"OBJECT", "trace_rating":"normal", "service_type":"OBS", "tracker_name":"obs-eg", "time":"1680859313271", "resource_name":"fangxin-sdk:SDK/nodejs-sdk.zip", "record_time":"1680859313271", "request_id":"000001875B05B4AB8411EF94DDE202C0", "user":{ "domain":{ "id":"1d60cc02b9814b9e8cab1ff36886cacb", "name":"hwstaff_pub_fcspaasw3" }, "name":"devuser", "id":"0d8880584b0090271f7cc00857a7c7b9" } } } 更多云服务事件源,请参见云服务事件源。 表11 参数说明 参数 类型 示例值 描述 datacontenttype String application/json 数据类型 data Map 见示例 数据 subject String 见示例 目标值 specversion String 1.0 版本 id String 见示例 唯一键值 source String eventSourceName 来源名称 time String 见示例 发布订阅时间 type String ROCKETMQ:CloudTrace:RocketmqCall 订阅类型
  • API Gateway 可以通过HTTPS调用FunctionGraph函数,使用API Gateway自定义REST API和终端节点来实现。可以将各个API操作(如GET和PUT)映射到特定的FunctionGraph函数,当向该API终端节点发送HTTPS请求时(APIG示例事件),API Gateway会调用相应的FunctionGraph函数。HTTPS调用触发函数的使用过程请参考使用APIG触发器。
  • 云审计 服务触发器CTS 可以编写FunctionGraph函数,根据CTS云审计服务类型和操作订阅所需要的事件通知,当CTS云审计服务获取已订阅的操作记录后,通过CTS触发器将采集到的操作记录作为参数传递(CTS示例事件)来调用FunctionGraph函数。经由函数对日志中的关键信息进行分析和处理,对系统、网络等业务模块进行自动修复,或通过短信、邮件等形式产生告警,通知业务人员进行处理。CTS触发器的使用请参考使用CTS触发器。
  • Node.js的initializer入口介绍 FunctionGraph目前支持以下Node.js运行环境: Node.js 6.10 (runtime = Node.js 6) Node.js 8.10 (runtime = Node.js 8) Nodejs 10.16(runtime = Node.js 10) Nodejs 12.13(runtime = Node.js 12) Node.js 14.18(runtime = Node.js 14) Node.js 16.17(runtime = Node.js 16) Node.js 18.15(runtime = Node.js 18)
  • Node.js函数接口定义 Node.js 6.10函数接口定义 export.handler = function(event, context, callback) 入口函数名(handler):入口函数名称, 需和函数执行入口处用户自定义的入口函数名称一致。 执行事件(event):函数执行界面由用户输入的执行事件参数, 格式为JSON对象。 上下文环境(context):Runtime提供的函数执行上下文,其接口定义在SDK接口说明。 回调函数(callback):callback方法完整声明为callback(err, message),用户通过此方法可以返回err和message至前台结果显示页面。具体的err或message内容需要用户自己定义,如字符串。
  • SDK接口 Context类中提供了许多上下文方法供用户使用,其声明和功能如表1所示。 getToken()、getAccessKey()和getSecretKey()方法返回的内容包含敏感信息,请谨慎使用,避免造成用户敏感信息的泄露。 表1 Context类上下文方法说明 方法名 方法说明 getRequestID() 获取请求ID。 getRemainingTimeInMilliSeconds () 获取函数剩余运行时间。 getAccessKey() 获取用户委托的AccessKey(有效期24小时),使用该方法需要给函数配置委托。 当前函数工作流已停止维护Runtime SDK 中getAccessKey接口,您将无法使用getAccessKey获取临时AK。 getSecretKey() 获取用户委托的SecretKey(有效期24小时),使用该方法需要给函数配置委托。 当前函数工作流已停止维护Runtime SDK 中getSecretKey接口,您将无法使用getSecretKey获取临时SK。 getSecurityAccessKey() 获取用户委托的SecurityAccessKey(有效期24小时),使用该方法需要给函数配置委托。 getSecuritySecretKey() 获取用户委托的SecuritySecretKey(有效期24小时),使用该方法需要给函数配置委托。 getSecurityToken() 获取用户委托的SecurityToken(有效期24小时),使用该方法需要给函数配置委托。 getUserData(string key) 通过key获取用户通过环境变量传入的值。 getFunctionName() 获取函数名称。 getRunningTimeInSeconds () 获取函数超时时间。 getVersion() 获取函数的版本。 getMemorySize() 分配的内存。 getCPUNumber() 获取函数占用的CPU资源。 getPackage() 获取函数组。 getToken() 获取用户委托的token(有效期24小时),使用该方法需要给函数配置委托。 getLogger() 获取context提供的logger方法,返回一个日志输出类,通过使用其info方法按“时间-请求ID-输出内容”的格式输出日志。 如调用info方法输出日志: logg = context.getLogger() logg.info("hello") getAlias 获取函数的别名
  • 执行结果 执行结果由3部分组成:函数返回、执行摘要和日志。 表2 执行结果说明 参数项 执行成功 执行失败 函数返回 返回函数中定义的返回信息。 返回包含错误信息和错误类型的JSON文件。格式如下: { "errorMessage": "", "errorType":"", } errorMessage:Runtime返回的错误信息 errorType:错误类型 执行摘要 显示请求ID、配置内存、执行时长、实际使用内存和收费时长。 显示请求ID、配置内存、执行时长、实际使用内存和收费时长。 日志 打印函数日志,最多显示4KB的日志。 打印报错信息,最多显示4KB的日志。
  • ZIP工程包示例 Nods.js工程ZIP包目录示例 Example.zip 示例工程包 |--- lib 业务文件目录 |--- node_modules npm三方件目录 |--- index.js 入口js文件(必选) |--- package.json npm项目管理文件 PHP工程ZIP包目录示例 Example.zip 示例工程包 |--- ext 扩展库目录 |--- pear PHP扩展与应用仓库 |--- index.php 入口PHP文件 Python工程ZIP包目录示例 Example.zip 示例工程包 |--- com 业务文件目录 |--- PLI 第三方依赖PLI目录 |--- index.py 入口py文件(必选) |--- watermark.py 实现打水印功能的py文件 |--- watermark.png 水印图片 Java工程ZIP包目录示例 Example.zip 示例工程包 |--- obstest.jar 业务功能JAR包 |--- esdk-obs-java-3.20.2.jar 第三方依赖JAR包 |--- jackson-core-2.10.0.jar 第三方依赖JAR包 |--- jackson-databind-2.10.0.jar 第三方依赖JAR包 |--- log4j-api-2.12.0.jar 第三方依赖JAR包 |--- log4j-core-2.12.0.jar 第三方依赖JAR包 |--- okhttp-3.14.2.jar 第三方依赖JAR包 |--- okio-1.17.2.jar 第三方依赖JAR包 Go工程ZIP包目录示例 Example.zip 示例工程包 |--- testplugin.so 业务功能包 C#工程ZIP包目录示例 Example.zip 示例工程包 |--- fssExampleCsharp2.0.deps.json 工程编译产生文件 |--- fssExampleCsharp2.0.dll 工程编译产生文件 |--- fssExampleCsharp2.0.pdb 工程编译产生文件 |--- fssExampleCsharp2.0.runtimeconfig.json 工程编译产生文件 |--- Handler 帮助文件,可直接使用 |--- HC.Serverless.Function.Common.dll 函数工作流提供的dll Cangjie工程ZIP包目录示例 fss_example_cangjie.zip 示例工程包 |--- libuser_func_test_success.so 业务功能包 定制运行时 Example.zip 示例工程包 |--- bootstrap 可执行引导文件
  • 打包规范说明 函数除了支持在线编辑代码,还支持上传ZIP、JAR、引入OBS文件等方式上传代码,上传操作过程请参见配置函数代码,函数工程的打包规范说明如表1所示。 表1 函数工程打包规范 编程语言 JAR包 ZIP包 OBS文件 Node.js 不支持该方式 假如函数工程文件保存在“~/Code/”文件夹下,在打包的时候务必进入Code文件夹下选中所有工程文件进行打包,确保入口函数是程序执行的入口,确保解压后,入口函数所在的文件位于根目录。 如果函数工程引入了第三方依赖,可以将第三方依赖打成ZIP包,在函数代码界面设置外部依赖包;也可以将第三方依赖和函数工程文件一起打包。 将工程打成ZIP包,上传到OBS存储桶。 PHP 不支持该方式 假如函数工程文件保存在“~/Code/”文件夹下,在打包的时候务必进入Code文件夹下选中所有工程文件进行打包,确保入口函数是程序执行的入口,确保解压后,入口函数所在的文件位于根目录。 如果函数工程引入了第三方依赖,可以将第三方依赖打成ZIP包,在函数代码界面设置外部依赖包;也可以将第三方依赖和函数工程文件一起打包。 将工程打成ZIP包,上传到OBS存储桶。 Python 2.7 不支持该方式 假如函数工程文件保存在“~/Code/”文件夹下,在打包的时候务必进入Code文件夹下选中所有工程文件进行打包,确保入口函数是程序执行的入口,确保解压后,入口函数所在的文件位于根目录。 如果函数工程引入了第三方依赖,可以将第三方依赖打成ZIP包,在函数代码界面设置外部依赖包;也可以将第三方依赖和函数工程文件一起打包。 将工程打成ZIP包,上传到OBS存储桶。 Python 3.6 不支持该方式 假如函数工程文件保存在“~/Code/”文件夹下,在打包的时候务必进入Code文件夹下选中所有工程文件进行打包,确保入口函数是程序执行的入口,确保解压后,入口函数所在的文件位于根目录。 如果函数工程引入了第三方依赖,可以将第三方依赖打成ZIP包,在函数代码界面设置外部依赖包;也可以将第三方依赖和函数工程文件一起打包。 将工程打成ZIP包,上传到OBS存储桶。 Java 8 如果函数没有引用第三方件,可以直接将函数工程编译成Jar包。 如果函数引用第三方件,将函数工程编译成Jar包后,将所有依赖三方件和函数JAR包打成ZIP包。 将工程打成ZIP包,上传到OBS存储桶。 Go 1.x 不支持该方式 必须在编译之后打ZIP包,编译后的二进制文件必须与执行函数入口保持一致,例如二进制名称为Handler,则执行入口为Handler。 将工程打成ZIP包,上传到OBS存储桶。 C# 不支持该方式 必须在编译之后打ZIP包,必须包含“工程名.deps.json”,“工程名.dll”,“工程名.runtimeconfig.json”,“工程名.pdb”和“HC.Serverless.Function.Common.dll”文件。 将工程打成ZIP包,直接上传到OBS存储桶。 定制运行时 不支持该方式 打ZIP包,必须包含“bootstrap”可执行引导文件。 将工程打成ZIP包,直接上传到OBS存储桶。 Cangjie 不支持该方式 必须在编译之后打ZIP包,编译后的二进制文件必须与执行函数入口保持一致,例如二进制名称为libuser_func_test_success.so,则执行入口为libuser_func_test_success.so。 将工程打成ZIP包,上传到OBS存储桶。
  • 执行结果 执行结果由3部分组成:函数返回、执行摘要和日志。 表3 执行结果说明 参数项 执行成功 执行失败 函数返回 返回函数中定义的返回信息。 返回包含错误信息和错误类型的JSON文件。格式如下: { "errorMessage": "", "errorType": "" } errorMessage:Runtime返回的错误信息 errorType:错误类型 执行摘要 显示请求ID、配置内存、执行时长、实际使用内存和收费时长。 显示请求ID、配置内存、执行时长、实际使用内存和收费时长。 日志 打印函数日志,最多显示4KB的日志。 打印报错信息,最多显示4KB的日志。
  • 函数Handler定义 ASSEMBLY::NAMESPACE.CLASSNAME::METHODNAME .ASSEMBLY为应用程序的.NET程序集文件的名称,假设文件夹名称为HelloCsharp。 NAMESPACE、CLASSNAME即入口执行函数所在的namespace和class名称。 METHODNAME即入口执行函数名称。例如: 创建函数时Handler:HelloCsharp::Example.Hello::Handler。
  • C#函数接口定义 FunctionGraph运行时目前支持C#(.NET Core 2.1)、C#(.NET Core 3.1)、C#(.NET Core 6.0)、.NET Core 8.0(仅支持“中东-利雅得”、“土耳其-伊斯坦布尔”区域)版本。 C#函数接口定义:作用域 返回参数 函数名(函数参数,Context参数) 作用域:提供给FunctionGraph调用的用户函数必须定义为public。 返回参数:用户定义,FunctionGraph负责转换为字符串,作为HTTP Response返回。 函数名:用户自定义函数名称,需要和函数执行入口处用户自定义的入口函数名称一致。 执行事件体:函数执行界面由用户输入的执行事件参数。 上下文环境(context):Runtime提供的函数执行上下文,相关属性定义在对象说明中。 HC.Serverless.Function.Common –部署在FunctionGraph服务中的项目工程需要引入该库,其中包含IFunctionContext对象,详情见context类说明。 创建csharp函数时,需要定义某个类中的方法作为函数执行入口,该方法可以通过定义IFunctionContext类型的参数来访问当前执行函数的信息。例如: 1 2 3 4 public Stream handlerName(Stream input,IFunctionContext context) { // TODO } C#函数的函数执行入口参数格式为:[程序集名]::[命名空间].[类名]::[执行函数名],例如CsharpDemo::CsharpDemo.Program::MyFunc,请参考函数执行入口通过FunctionGraph控制台进行配置或修改。 建议使用.NET Core 3.1版本。
  • SDK接口 Context接口 Context类中提供了许多属性供用户使用,如表1所示。 表1 Context对象说明 属性名 属性说明 String RequestId 请求ID。 String ProjectId Project Id。 String PackageName 函数所在分组名称。 String FunctionName 函数名称。 String FunctionVersion 函数版本。 Int MemoryLimitInMb 分配的内存。 Int CpuNumber 获取函数占用的CPU资源。 String Accesskey 获取用户委托的AccessKey(有效期24小时),使用该方法需要给函数配置委托。 当前函数工作流已停止维护Runtime SDK 中String AccessKey接口,您将无法使用String AccessKey获取临时AK。 String Secretkey 获取用户委托的SecretKey(有效期24小时),使用该方法需要给函数配置委托。 当前函数工作流已停止维护Runtime SDK 中String SecretKey接口,您将无法使用String SecretKey获取临时SK。 String SecurityAccessKey 获取用户委托的SecurityAccessKey(有效期24小时),使用该方法需要给函数配置委托。 String SecuritySecretKey 获取用户委托的SecuritySecretKey(有效期24小时),使用该方法需要给函数配置委托。 String SecurityToken 获取用户委托的SecurityToken(有效期24小时),使用该方法需要给函数配置委托。 String Token 获取用户委托的Token(有效期24小时),使用该方法需要给函数配置委托。 Int RemainingTimeInMilliSeconds 函数剩余运行时间。 String GetUserData(string key,string defvalue=" ") 通过key获取用户通过环境变量传入的值。 日志接口 FunctionGraph中C# SDK中接口日志说明如所示。 表2 日志接口说明 方法名 方法说明 Log(string message) 利用context创建logger对象: var logger = context.Logger; logger.Log("hello CSharp runtime test(v1.0.2)"); Logf(string format, args ...interface{}) 利用context创建logger对象: var logger = context.Logger; var version = "v1.0.2" logger.Logf("hello CSharp runtime test({0})", version);
  • 出口插件 实现Exit插件。 devspore-horizon提供了接口Observer,用户需要实现这个接口的observe(DataEvent dataEvent)方法,把变更通知、更新缓存、统一审计、统一工作流的处理逻辑写到此方法体内即可。 Observer代码如下: public interface Observer { // receive the BO changes void observe(DataEvent dataEvent) throws PluginException; } 填写配置信息。 完成接口实现之后,还需要填写配置信息。有关horizon的出口拦截配置信息如下: devspore.horizon.observers devspore.horizon.observers配置项也是个数组。horizon会读取数组中每个bean id,执行已实现的消息发送、审计等逻辑。 多个插件以","分隔,多个插件按配置顺序执行。 devspore: horizon: observers: bean1,bean2
  • 内置插件 开启horizon后,会自动生成两个内置插件,用户在插件中实现统一的操作前认证、鉴权,操作后消息发送、缓存更新、审计等逻辑即可: Entry插件 /** * default request plugin */ @Component @javax.annotation.Generated(value = "com.huaweicloud.devspore.codegen, xxx-RELEASE") public class DefaultRequestPlugin extends Processor { @Override public boolean doProcess(DataEvent dataEvent) throws PluginException { // do your code return true; } } Exit插件 /** * default response plugin */ @Component @javax.annotation.Generated(value = "com.huaweicloud.devspore.codegen, xxx-RELEASE") public class DefaultResponsePlugin implements Observer { @Override public void observe(DataEvent dataEvent) throws PluginException { // do your code } } 配置文件 devspore: horizon: processors: defaultRequestPlugin observers: defaultResponsePlugin
  • 入口插件 实现Entry插件。 devspore-horizon提供了抽象类Processor,用户需要继承这个抽象类,实现抽象方法doProcess(DataEvent event),把认证和鉴权的处理逻辑写到此方法体内。此方法返回值为boolean型。如果认证或者鉴权的逻辑失败,则返回false,责任链后续节点不再执行,整个请求返回不再执行;如果认证或者鉴权成功,则返回为true,继续执行后续节点。Processor代码如下: public abstract class Processor { protected MetaDocument metaDoc; private String name; private Processor next; public Processor getNext() { return next; } public void setNext(Processor next) { this.next = next; } public boolean process(DataEvent dataEvent) throws PluginException { if (!doProcess(dataEvent)) { return false; } if (null != next) { return next.process(dataEvent); } return true; } public abstract boolean doProcess(DataEvent dataEvent) throws PluginException; public String getName() { return name; } } 填写配置信息。 完成接口实现之后,还需要填写配置信息。有关horizon的入口拦截配置信息如下: devspore.horizon.approvers 实现的Entry插件,插件必须注入到spring IOC容器,并提供bean id,赋值给devspore.horizon.processors配置项。devspore.horizon.processors配置项是个数组。horizon会读取数组中每个bean id,执行已实现的鉴权、认证等逻辑。 多个插件以","分隔,多个插件按配置顺序执行。 devspore: horizon: processors: bean1,bean2
  • devspore-probe常用的配置参数如下所示 devspore: probe: metrics: tags: component: devspore-application # 应用名称,使监控指标带上应用标签 api-description-tags: false # 是否开启http_server_request指标添加description标签功能 aom: enable: false # 是否开启监控数据上报 AOM 平台功能 authentication:AccessCode # 监控数据上报AOM的鉴权方式,可选值:AccessCode,AccessKey ak: ${aom_ak} # 用户AK sk: ${aom_sk} # 用户SK url: ${aom_url} # 监控数据上报AOM平台接口URL access-code:${aom_accessCode} # 选择AccessCode配置 push-interval-seconds: 60 # 监控数据上报AOM平台的采集间隔,单位:秒 pattern: # 符合该正则表达式的监控项将被上报到AOM,默认上报所有的监控项 external-env-info: false # 是否在监控数据中加入serviceStage环境变量 batch-size:60 # 每批次上传AOM平台的Body包包含的监控项数量,默认值60
  • 参数说明 表1 参数说明 参数名称 默认值 类型 被监控组件或应用名称 devspore.probe.metrics.tags.component - String 被监控组件或应用名称。 devspore.probe.metrics.api-description-tags false boolean 是否开启http_server_request指标添加description标签功能,如开启,会自动添加@ApiOperation注解的value字段或@Operation注解的summary字段作为description值。 devspore.probe.aom.enable false boolean 是否开启监控数据上报AOM平台功能。 devspore.probe.aom.authentication - String 监控数据上报AOM的鉴权方式,可选值:AccessCode,AccessKey。 当选择AccessCode时,url、access-code必须配置。 当选择AccessKey时,url、ak、sk必须配置。 devspore.probe.aom.ak - String 用户AK。 devspore.probe.aom.sk - String 用户SK。 devspore.probe.aom.access-code - String 用户AccessCode。 devspore.probe.aom.apig-app-code - String 被授权服务的appCode、非必须使用,非内部用户使用AccessCode鉴权方式的时候需要配置此配置。 devspore.probe.aom.url - String 监控数据上报AOM平台接口URL。 devspore.probe.aom.push-interval-seconds 60 int 监控数据上报AOM平台的采集间隔,单位:秒。 devspore.probe.aom.pattern /w* String 符合该正则表达式的监控项将被上报到AOM,默认上报所有的监控项。 devspore.probe.aom.external-env-info false boolean 是否在监控数据中加入serviceStage环境变量。 devspore.probe.aom.batch-size false int 每批次上传AOM平台的Body包包含的监控项数量,默认值60。
  • request日志字段说明 表1 request日志字段说明 字段名 字段含义 可选/必选 logType 日志类型 必选,值固定为request url 请求URL 必选 path 请求路径 必选 method 请求HTTP方法 必选 status 返回状态码 必选 startTime 请求开始时间 必选 duration 请求时长 必选 clientIp 请求方IP 必选 clientType 客户端类型 必选 userId 请求所属用户ID 必选 reqBodySize 请求体body大小 必选 resBodySize 返回体body大小 必选 nenvId 调用方服务 APM 环境ID 必选(依赖APM) senvId 被调用服务APM环境ID 必选(依赖APM) tracId 调用链跟踪ID 必选(依赖APM)
  • 实现原理 devspore-http-log打印请求日志是通过实现常见HTTP请求客户端的拦截器来完成的。拦截器可以在请求发送之前和响应返回之后对数据进行处理,从而实现日志记录。 例如,在Spring Boot中,可以通过实现ClientHttpRequestInterceptor接口并重写intercept方法来创建自定义拦截器。在拦截器中,可以添加日志记录逻辑,以打印请求和响应的详细信息。此外,还可以通过RestTemplateCustomizer将自定义拦截器注册到RestTemplate中,从而实现对HTTP请求和响应的全局日志记录。 这种实现方式的优点是通用性强、代码侵入性小,并且具有可定制性。通过拦截器,可以在不修改业务逻辑代码的情况下,轻松地添加日志记录功能。 目前支持的客户端有:httpclient、okhttp、RestTemplate和Feign。
  • request日志示例 "nenvId": "null", "userId": "null", "url": "http://localhost:8081/servicecall/consumer/001", "path": "/servicecall/consumer/001", "method": "GET", "senvId": null, "status": 200, "tracId": null, "startTime": "2023-12-28 16:59:41.218", "duration": 33, "clientType": "httpClient.HttpResponseProxy", "clientIp": "169.254.174.247", "reqBodySize": 0, "resBodySize": 93, "logType": "request" }
  • 使用方式 HttpClient 前提:需要使用httpclient进行对第三方的调用。 需要用户在创建CloseableHttpClient时添加com.huaweicloud.devspore.http.log.httpclient.HttpClientRequestInterceptor和com.huaweicloud.devspore.http.log.httpclient.HttpClientReponseInterceptor。 示例: CloseableHttpClient httpClient = HttpClients.custom() .addInterceptorFirst(new HttpClientRequestInterceptor()) .addInterceptorFirst(new HttpClientResponseInterceptor()) .build(); OkHttp 前提:需要使用okhttp进行对第三方的调用。 需要用户在创建OKhttpclient时添加com.huaweicloud.devspore.http.log.okhttp.OkhttpInterceptor。 示例: OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new OkhttpInterceptor()).build(); RestTemplate 注意:若存在使用restTemplate传输大文件或者大对象的场景,请不要使用此拦截器记录requestLog,否则极有可能引入OOM问题。 前提:需要使用restTemplate进行对第三方的调用。 以bean形式注入的restTemplate。 需要在spring配置文件中添加配置项:devspore.http-log.request.rest-template.enable=true。 当devspore.http-log.request.enable(默认值true)和devspore.http-log.request.rest-template.enable(默认值false)两个配置项同时为true时,才会自动添加RestTemplateInterceptor。 原理:当配置条件允许使用RestTemplateInterceptor时,httplog组件会扫描服务中所有的RestTemplate类型的bean,并为其添加RestTemplateInterceptor拦截器。 相关源码见:com.huaweicloud.devspore.http.log.config.DevsporeHttpLogAutoConfiguration.setApplicationContext() 非bean形式注入的restTemplate。 需要用户在创建restTemplate时添加com.huaweicloud.devspore.http.log.resttemplate.RestTemplateInterceptor。 RestTemplate restTemplate = new RestTemplate(); restTemplate.getInterceptors().add(0, new RestTemplateInterceptor()); Feign 前提:需要使用Feign Client进行对第三方的调用。 当使用Feign的时候,无需做其他改动,devspore-http-log会自动打印request日志,如不想打印request日志,可以在spring配置文件中添加配置:devspore.http-log.request.enable=false来关闭request日志的打印。
  • 数据准备 此处需要提前准备示例使用的数据库表,并初始化一些软删除功能示例使用的测试数据,具体的建表语句如下: CREATE TABLE `t_order` ( `id` varchar(40) NOT NULL COMMENT 'id', `name` varchar(200) NOT NULL, `soft_delete_flag` bigint(0) NOT NULL DEFAULT '0' COMMENT '软删除标记字段,为时间戳表示此数据执行了软删除操作,时间戳记录了软删除的时间,为0表示没有执行软删除操作;searchable', PRIMARY KEY (`id`) ) COMMENT = 'primaryKeyType("UUID")'; INSERT INTO `softdelete`.`t_order`(`id`, `name`, `soft_delete_flag`) VALUES ('1', 'test1', 0); INSERT INTO `softdelete`.`t_order`(`id`, `name`, `soft_delete_flag`) VALUES ('2', 'test2', 0); INSERT INTO `softdelete`.`t_order`(`id`, `name`, `soft_delete_flag`) VALUES ('3', 'test3', 0); INSERT INTO `softdelete`.`t_order`(`id`, `name`, `soft_delete_flag`) VALUES ('4', 'test4', 0); INSERT INTO `softdelete`.`t_order`(`id`, `name`, `soft_delete_flag`) VALUES ('5', 'test5', 0); INSERT INTO `softdelete`.`t_order`(`id`, `name`, `soft_delete_flag`) VALUES ('6', 'test6', 0); INSERT INTO `softdelete`.`t_order`(`id`, `name`, `soft_delete_flag`) VALUES ('7', 'test7', 0); INSERT INTO `softdelete`.`t_order`(`id`, `name`, `soft_delete_flag`) VALUES ('8', 'test8', 0); INSERT INTO `softdelete`.`t_order`(`id`, `name`, `soft_delete_flag`) VALUES ('9', 'test9', 0); INSERT INTO `softdelete`.`t_order`(`id`, `name`, `soft_delete_flag`) VALUES ('10', 'test10', 0); INSERT INTO `softdelete`.`t_order`(`id`, `name`, `soft_delete_flag`) VALUES ('11', 'test11', 0); INSERT INTO `softdelete`.`t_order`(`id`, `name`, `soft_delete_flag`) VALUES ('12', 'test12', 0);
  • 原理 AstroPro实现多租隔离的方式是通过在需要做资源隔离的对象上额外生成一个tenant_id的字段来存储租户信息,在用户访问接口时,将调用者的租户信息存放在线程变量中(存放方式在用户自定义租户id获取接口中详细说明),通过对比线程中的租户信息和对象中的租户信息是否一致来实现租户隔离的。 用户需要在业务代码中添加租户相关的校验逻辑,具体逻辑如下: 新增时:需要在业务代码中将tenant_id设置到新增对象中。 查询时:先查出数据,再判断查出对象的tenant_id值是否和当前线程tenant_id匹配,只有匹配时才返回,不匹配时证明操作的不是当前租户的资源,此次请求不合法,抛出异常。 修改、删除时:先查出数据,再判断查出对象的tenant_id值是否和当前线程tenant_id匹配,只有匹配后才进行后续的修改或删除操作。 在生成用户自定义租户id获取接口代码时,以上相关的逻辑都会生成出来,用户在做后续的业务代码编写中应注意不要删除相关的代码。此外在自定义API中如涉及以上场景,用户需要手动添加相关校验逻辑。
  • access日志字段说明 表1 access日志字段说明 字段名 字段含义 可选/必选 对应配置参数 logType 日志类型 必选,值固定为 access 无 service 微服务名称 必选,通过配置文件配置 devspore.http-log.service-name serviceAppId 微服务的AppID 必选,通过配置文件配置 devspore.http-log.service-app-id nenvId 调用方服务APM环境ID 必选 无 senvId Server端APM环境ID 必选 无 url 请求URL 必选 无 path 请求路径(去参数可聚合统计) 必选 无 method 请求HTTP方法 必选 无 params 请求参数 可选,默认值为null devspore.http-log.params reqBodySize 请求体body大小 必选 无 resBodySize 返回体body大小 必选 无 appId HIS网关appId 必选 devspore.http-log.app-id-key status 返回状态码 必选 无 traceId 调用链跟踪ID 必选 无 startTime 请求开始时间 必选 无 duration 请求时长 必选 无 clientIp 请求方IP 必选 无 userId 请求所属用户ID 必选 无 olcDryRun 是否开启olc干跑 可选 devspore.http-log.olc olcBlockMsg olc限流信息 可选 devspore.http-log.olc subToken 截断token 可选 devspore.http-log.sub-token cpuCost 当前请求所占用的cpu时间-单位(纳秒) 可选 devspore.http-log.access.resource-cost memCost 当前请求使用的内存-单位byte 可选 devspore.http-log.access.resource-cost sqlReadRows 当前请求共查询了多少行数据库记录 可选 devspore.http-log.access.sql-rows sqlAffectedRows 当前请求共影响了多少行数据库记录 可选 devspore.http-log.access.sql-rows
  • access日志示例 "logType": "access", "traceId": null, "nenvId": null, "method": "GET", "resBodySize": 93, "params": null, "userId": null, "url": "http://localhost:8081/servicecall/consumer/001", "duration": 90, "path": "/consumer/{consumer_id}", "senvId": null, "service": "servicecall", "clientIp": "127.0.0.1", "appId": null, "startTime": "2023-12-25 09:33:30.589", "reqBodySize": -1, "status": 200 }
  • 依赖情况 以下为本组件的具体依赖情况: com.huaweicloud.devspore:swagger-extension 表1 swagger-extension组件依赖 依赖组件 版本 scope org.projectlombok:lombok 1.18.32 compile com.huaweicloud.devspore:swagger-extension-springfox 表2 swagger-extension-springfox组件依赖 依赖组件 版本 scope org.springframework:spring-context 5.3.39 provided com.huaweicloud.devspore:swagger-extension ${devspore-swagger-extension.version} compile org.springframework.boot:spring-boot-autoconfigure 2.7.18 provided org.springframework.boot:spring-boot-configuration-processor 2.7.18 optional org.springframework:spring-webmvc 5.3.39 provided io.springfox:springfox-core 3.0.0 provided io.springfox:springfox-swagger2 3.0.0 provided io.springfox:springfox-spi 3.0.0 provided io.springfox:springfox-schema 3.0.0 provided org.mapstruct:mapstruct 1.5.5.Final provided 父主题: devspore-swagger-extension使用指南
  • 使用说明 在编辑服务时,业务设计界面选中需要进行软删除的对象,勾选软删除策略和恢复软删除后生成代码,如下所示: 图1 设置软删除策略 当勾选了“软删除策略”后,生成的代码会有如下变化: 在勾选软删除策略的对象上会额外生成一个字段 (`soft_delete_flag` bigint(20) NOT NULL DEFAULT '0')。 删除和批量删除的API上会额外生成一个Boolean类型的参数hardDeletion,在调用删除相关API时,如果hardDeletion传入true则进行物理删除,否则进行逻辑删除。 查询API上会额外生成一个Boolean类型的参数softDeleted,当不传入softDeleted或softDeleted传入false的时候,只查询未被删除数据(soft_delete_flag = 0 的数据)。当softDeleted参数为true时,查询将仅基于主键进行,忽略soft_delete_flag的值。 批量查询API中soft_delete_flag字段会作为一个非必填的参数添加到请求参数中。 当勾选了“恢复软删除”后,生成的代码会有如下变化: 额外生成两个API,一个是单条数据的恢复软删除(将被删除的数据的soft_delete_flag重新设置为0),一个是批量数据的恢复软删除。
  • method日志字段说明 表1 method日志字段说明 字段名 字段含义 可选/必选 logType 日志类型。 必选,值固定为methodLog serviceName 服务名称:取配置文件中:devspore.http-log.service-name的值。 必选 className 方法所在类的全路径限定名。 必选 methodName 方法名称。 必选 exceptionClass 方法异常后异常类全路径限定名(包名使用首字母缩写),方法无异常时此字段为null。 必选 startTime 方法开始调用时间。 必选 duration 方法耗时(单位:ms)。 必选 traceId 调用链跟踪ID。 必选(依赖APM)
共100000条