如何使用Azure云功能将所有Azure存储队列消息批处理为Blob?

时间:2018-02-18 19:54:09

标签: azure azure-storage-blobs azure-functions azure-storage-queues

我想阅读Azure队列存储的所有消息并将它们写入Blob。理想情况下,我想阅读10000或更多的批次,并将它们写入Blob。

我正在使用带有队列存储绑定的Azure云功能进行输入和Blob存储绑定输出,但我无法找到能够让我读取多条消息的API或配置选项。 有谁知道这样的API?

2 个答案:

答案 0 :(得分:3)

官方文档未提及在Azure Function的单次执行中批量处理Storage Queue消息的任何支持。有an open issue in WebJobs SDK。所以,它不受支持。

如果您可以灵活地使用哪种服务用于消息传递中间件,则可以切换到事件中心。 Event Hub触发器支持(并鼓励)批量处理消息。但它不可能是10.000:批量大小限制为256k的数据。

要批量处理存储队列消息,您必须远离队列触发函数(例如,在计时器上运行函数并连接到表存储以处理所有消息,或者具有自定义轮询Web作业,或者使用带有自定义触发器的Web Job SDK。

答案 1 :(得分:0)

我终于找到了一个我非常满意的解决方案。 使用缓冲区是不可扩展的,因为运行时很容易超过Azure Functions运行时强加的5分钟限制,加上明显的内存消耗问题,而且我不得不使用定时器触发器,所以我需要以某种方式确保所有相关消息都在在某个时间排队。

我现在所做的是使用普通队列绑定来获取消息,以及节点存储SDK,以实现某种"假的"流入附加Blob。因此,每条消息都会逐个转换为CSV行,并附加到相应的blob。

以下是该功能的代码:

const config = require('./config/config.js')
const storage = require('azure-storage')
const csvTransformer = require('./lib/csvTransform')
const async = require('async')

module.exports = function (context, myQueueItem) {
  context.log(
    'JavaScript queue trigger function processed work item',
    myQueueItem
  )

  let blobService = storage.createBlobService(config.targetBlobConnection)
  let messageDayString = csvTransformer.determineDayFromMessage(myQueueItem)
  let blobName = messageDayString + '.csv'
  let csvMessage
  async.waterfall(
    [
      function (callback) {
        blobService.createContainerIfNotExists(
          config.targetBlobContainer,
          { publicAccessLevel: 'blob' },
          err => {
            callback(err)
          }
        )
      },
      function (callback) {
        blobService.doesBlobExist(
          config.targetBlobContainer,
          blobName,
          null,
          (err, blobResult) => {
            context.log('got blobResult: ', blobResult)
            callback(err, blobResult)
          }
        )
      },
      function (blobResult, callback) {
        if (blobResult && blobResult.exists) {
          csvMessage = csvTransformer.transformMessageToCSV(myQueueItem, false)
          blobService.appendFromText(
            config.targetBlobContainer,
            blobName,
            csvMessage,
            null,
            (err, appendedBlobResult) => {
              context.log('appended to existing blob: ', appendedBlobResult)
              callback(err, appendedBlobResult)
            }
          )
        } else {
          csvMessage = csvTransformer.transformMessageToCSV(myQueueItem, true)
          blobService.createAppendBlobFromText(
            config.targetBlobContainer,
            blobName,
            csvMessage,
            null,
            (err, createdBlobResult) => {
              context.log('created new blob: ', createdBlobResult)
              callback(err, blobResult)
            }
          )
        }
      }
    ],
    function (err, result) {
      if (err) {
        context.log.error('Error happened!')
        context.log.error(err)
        context.done(err)
      } else {
        context.log('appended CSV message to blob')
        context.bindings.outputQueueItem = csvMessage
        context.done()
      }
    }
  )
}