全部产品
存储与CDN 数据库 安全 应用服务 数加·人工智能 数加·大数据基础服务 互联网中间件 视频服务 开发者工具 解决方案 物联网

应用示例4 - 触发器管理

更新时间:2017-11-10 17:55:36

背景信息

有些时候,用户可能不想通过直接调用的方式来执行函数,例如一个应用可能已经使用对象存储(Object Storage Service,简称OSS)来存放用户上传的图片,用户可以实现一个函数去下载图片进行处理,并将结果存入OSS或者其他服务。如果OSS能够帮助我们关注新上传的图片,并且自动的去调用执行相应函数,用户就不需要再去自己调用函数了,从而简化了开发和使用流程。OSS是如何知道关注这些事件并且调用函数计算的函数呢?这就是这个示例中要介绍的触发器(Trigger)的作用。

函数计算提供了一种事件驱动的计算模型。函数的执行是由事件驱动的,在前面的示例中,函数的执行都是用CLI来触发的,但是它也可以由其它一些事件源来触发。目前函数计算支持OSS作为事件源,以后会陆续集成其它事件源。和数据库中的触发器概念类似,函数计算触发器描述了一组规则,当某个事件满足这些规则,事件源就会触发相应的函数。简单说来,在这个示例中,一个被存入OSS的文件,如果它是以source/为前缀,那么OSS就会自动的调用相应的函数。

通过示例,您将了解:

  • 如何使用存放在OSS的函数代码来创建函数
  • 如何使用OSS触发器来连接OSS和函数计算从而自动处理存入OSS的文件

这里的目标是当一个图片以source/为前缀存入OSS后,希望这个图片被缩放,然后以processed/为前缀存入OSS。例如source/serverless.png会被处理成processed/serverless.png

本示例会对示例三 中的函数进行改造,输入不再是一个图片,而是OSS事件(event),处理后的图片也不再作为函数的执行结果返回,而是被存放回OSS。

本示例假定:

  • 有一个 fc-codebucket 来存放函数代码。创建函数时函数计算会从这个bucket复制代码。
  • 有一个 image-albumbucket,原图片前缀为 source/,处理后的图片前缀为processed/

注意:

在实际操作中,您需要将上面的bucket替换成自己的bucket。您也可以使用同一个bucket来完成本示例。这个可以去oss控制台去创建,特别注意endpoint要和自己的一致。

更新服务角色(ServiceRole)

示例三中,我们创建了fc-logsrole,并授权函数计算可以扮演这个角色往Loghub中写日志。在这个例子中,需要添加更多授权到这个角色:

  • 可以读取fc-codebucket的对象,从而在创建函数的时候函数计算可以从这个bucket里复制代码。
  • 可以读取image-albumbucket的对象,并且写入新的对象,从而函数在执行的时候可以从这个bucket里读取图片,处理结束后写入这个bucket。
  1. mkrp fc-copy-code-all -a '"oss:GetObject"' -r '"*"'
  2. attach -p /ram/policies/fc-copy-code-all -r /ram/roles/fc-logs
  3. mkrp fc-oss-rw -a '["oss:GetObject", "oss:PutObject"]' -r '"*"'
  4. attach -p /ram/policies/fc-oss-rw -r /ram/roles/fc-logs

注意: 如果有遇到问题,可以去该页面的最后一行点击进入完整demo shell 操作视频查看

创建函数

上传代码到OSS

在code目录下,创建“oss_image_process.js”文件,实现名为”resize”的函数,内容如下:

  1. 'use strict';
  2. console.log('Loading function ...');
  3. var oss = require('ali-oss').Wrapper;
  4. var fs = require('fs');
  5. var jimp = require("jimp");
  6. module.exports.resize = function (eventBuf, ctx, callback) {
  7. console.log('Received event:', eventBuf.toString());
  8. var event = JSON.parse(eventBuf);
  9. var ossEvent = event.events[0];
  10. // Required by OSS sdk: OSS region is prefixed with "oss-", e.g. "oss-cn-shanghai"
  11. var ossRegion = "oss-" + ossEvent.region;
  12. // Create oss client.
  13. var client = new oss({
  14. region: ossRegion,
  15. // Credentials can be retrieved from context
  16. accessKeyId: ctx.credentials.accessKeyId,
  17. accessKeySecret: ctx.credentials.accessKeySecret,
  18. stsToken: ctx.credentials.securityToken
  19. });
  20. // Bucket name is from OSS event
  21. client.useBucket(ossEvent.oss.bucket.name);
  22. // Processed images will be saved to processed/
  23. var newKey = ossEvent.oss.object.key.replace("source/", "processed/");
  24. var tmpFile = "/tmp/processed.png";
  25. // Get object
  26. console.log('Getting object: ', ossEvent.oss.object.key)
  27. client.get(ossEvent.oss.object.key).then(function (val) {
  28. // Read object from buffer
  29. jimp.read(val.content, function (err, image) {
  30. if (err) {
  31. console.error("Failed to read image");
  32. callback(err);
  33. return;
  34. }
  35. // Resize the image and save it to a tmp file
  36. image.resize(128, 128).write(tmpFile, function (err) {
  37. if (err) {
  38. console.error("Failed to write image locally");
  39. callback(err);
  40. return;
  41. }
  42. // Putting object back to OSS with the new key
  43. console.log('Putting object: ', newKey);
  44. client.put(newKey, tmpFile).then(function (val) {
  45. console.log('Put object:', val);
  46. callback(null, val);
  47. return;
  48. }).catch(function (err) {
  49. console.error('Failed to put object: %j', err);
  50. callback(err);
  51. return
  52. });
  53. });
  54. });
  55. }).catch(function (err) {
  56. console.error('Failed to get object: %j', err);
  57. callback(err);
  58. return
  59. });
  60. };
  1. # -*- coding: utf-8 -*-
  2. import oss2, json
  3. from wand.image import Image
  4. def resize(event, context):
  5. evt = json.loads(event)
  6. creds = context.credentials
  7. # Required by OSS sdk
  8. auth=oss2.StsAuth(
  9. creds.access_key_id,
  10. creds.access_key_secret,
  11. creds.security_token)
  12. evt = evt['events'][0]
  13. bucket_name = evt['oss']['bucket']['name']
  14. endpoint = 'oss-' + evt['region'] + '.aliyuncs.com'
  15. bucket = oss2.Bucket(auth, endpoint, bucket_name)
  16. objectName = evt['oss']['object']['key']
  17. # Processed images will be saved to processed/
  18. newKey = objectName.replace("source/", "processed/")
  19. remote_stream = bucket.get_object(objectName)
  20. if not remote_stream:
  21. return
  22. remote_stream = remote_stream.read()
  23. with Image(blob=remote_stream) as img:
  24. with img.clone() as i:
  25. i.resize(128, 128)
  26. new_blob = i.make_blob()
  27. bucket.put_object(newKey, new_blob)

打包:由于在示例三中已经安装了jimp,这里就不需要再下载了。上面的代码中还用到了aliyun OSS的javascript SDK,函数计算的nodejs6运行环境(runtime)已经包含这个包,因此这里也不需要下载了。

然后,需要将打包后的代码上传到OSS,下面的命令行使用了ossutil,如果你没有安装ossutil,也可以直接去OSS的控制台把code.zip上传到fc-code bucket(注意:这个fc-code bucket endpoint要和自己的设置的endpoint相同)。

  1. cd code
  2. ls
  3. # hello_world.js image_process.js node_modules oss_image_process.js
  4. zip -r code.zip .
  5. ossutil -e http://oss-cn-shanghai.aliyuncs.com cp code.zip oss://fc-code/code.zip

注意:上面的操作是普通的linux命令,不是在函数计算CLI的shell模式中进行的

创建函数

  1. mkf demo/resize_oss_image -t nodejs6 -h oss_image_process.resize -b fc-code -o code.zip

-b指定了代码存放的bucket

-o指定了代码在bucket中的object key

创建触发器

在创建触发器之前,需要创建一个调用角色,OSS会扮演这个角色来调用执行函数。

  1. mkir fc-invoke-function
  2. mkrp fc-invoke-all -a '"fc:InvokeFunction"' -r '"*"'
  3. attach -p /ram/policies/fc-invoke-all -r /ram/roles/fc-invoke-function

创建触发器

  1. cd demo/resize_oss_image
  2. mkt resize_image -t oss -r acs:ram::12345:role/fc-invoke-function -s acs:oss:cn-shanghai:12345:image-album -c resize_image_config.yaml

-t指定了触发器的类型,目前仅支持oss

-r指定了oss扮演的角色来调用函数,您需要将12345换成您的阿里云Account ID

-s指定了事件源的bucket资源地址(ARN),您需要将12345换成您的阿里云Account ID,将image-album换成您的bucket

-c指定了OSS触发器的配置,resize_image_config.yaml的内容如下:

  1. triggerConfig:
  2. events:
  3. - oss:ObjectCreated:PostObject
  4. - oss:ObjectCreated:PutObject
  5. filter:
  6. key:
  7. prefix: source/

测试触发器

上传一个图片到image-album/source。如果你没有安装ossutil,也可以去OSS控制台上传图片。

  1. ossutil -e http://oss-cn-shanghai.aliyuncs.com cp data/serverless.png oss://image-album/source/serverless.png
  2. ossutil -e http://oss-cn-shanghai.aliyuncs.com ls oss://image-album/processed/

需要特别注意的是,在上面的触发器配置中,用户让OSS仅关注以source为前缀的上传对象,处理结果存入以processed为前缀的对象。这个前缀隔离尤其重要,如果您误将结果存入以source为前缀的对象,那这个对象又会触发调用函数,导致无限循环,从而造成不必要的开销。

示例4 完整demo操作视频,请点击 oss_image_process

本文导读目录