Согласно связям с хранилищем Azure Blob для документации Azure Functions, при настройке триггера blob вы можете использовать сопоставление образцов по имени blob для отображения частей пути к переменным в функции, например.
[FunctionName("BlobTriggered")]
public static void BlobTriggered(
[BlobTrigger("myContainer/{name}.{extension}")] Stream myBlob,
string name,
string extension,
TraceWriter log)
{
// Given the blob path "myContainer/myBlob.png":
// name == "myBlob"
// extension == "png"
}
Я тестировал это, и он BlobTrigger
работает для моего использования, однако из-за больших задержек при стрельбе BlobTrigger
(часто свыше 5 минут) это не жизнеспособный вариант. В результате я хочу сделать это триггером Event Grid вместо предложения по шкале Azure Functions и документации для хостинга:
Когда вы используете триггер blob на плане потребления, может быть до 10-минутной задержки при обработке новых блоков. Эта задержка возникает, когда приложение-приложение перестает работать. После того, как приложение функции запущено, blobs обрабатываются немедленно. Чтобы избежать этой задержки холодного запуска, используйте план обслуживания приложений с включенным включенным включением или используйте триггер Event Grid.
Есть ли способ получить такое же поведение соответствия шаблонов из привязки ввода вместо триггера?
В моей конкретной ситуации я установил подписку на EventGrid
для создания blob, которая запускает функцию оркестра, вызывающую функцию активности, чтобы читать и анализировать blobs:
[FunctionName("NewBlobCreated")]
public static async Task NewBlobCreated(
[EventGridTrigger]EventGridEvent eventGridEvent,
[OrchestrationClient]DurableOrchestrationClient starter,
ILogger log)
{
// Start our orchestrator function to read the file
string instanceId = await starter.StartNewAsync(
"OrchestrateBlobReader",
eventGridEvent);
}
// Orchestrator function
[FunctionName("OrchestrateBlobReader")]
public static async Task OrchestrateBlobReader(
[OrchestrationTrigger] DurableOrchestrationContext context,
ILogger log)
{
var eventGridEvent = context.GetInput<EventGridEvent>();
var parsedBlob = await context.CallActivityAsync<string>("ReadBlob", eventGridEvent.Data);
...
}
[FunctionName("ReadBlob")]
public static async Task<string> ReadBlob(
[ActivityTrigger] JObject eventData,
[Blob("{data.url}", FileAccess.Read)]CloudBlockBlob blob,
ILogger log)
{
using (var blobStream = await blob.OpenReadAsync())
{
// Blob is able to be read from blobStream here
...
}
}
В идеале я хотел бы, чтобы моя функция ReadBlob
себя аналогично функции BlobTriggered
из первого примера выше, чтобы сделать что-то в следующих строках:
[FunctionName("ReadBlob")]
public static async Task<string> ReadBlob(
[ActivityTrigger] JObject eventData,
[Blob("{data.url}", FileAccess.Read)]CloudBlockBlob blob,
string extension,
ILogger log)
{
if (extension.Equals("txt", StringComparison.OrdinalIgnoreCase))
{ ... }
else if (extension.Equals("png", StringComparison.OrdinalIgnoreCase)
{ ... }
else
{ ... }
}
Проблема в том, что я не вижу никакого способа привязать параметр extension
к связыванию ввода Blob
как это делал для BlobTrigger
- в BlobTrigger
с тем, что путь связан с URL-адресом, предоставленным EventGridEvent
в виде eventData
JObject
eventData
JObject
.
Можно ли в этом случае достичь такой же функции сопоставления шаблонов? Или мне придется самостоятельно проанализировать строку пути, чтобы извлечь соответствующую информацию?
BindingTemplateSource
исходный код привязки триггера blob - мое "быстрое и грязное" решение заключалось в том, чтобы использовать базовый класс BindingTemplateSource
который триггер использует для сопоставления пути и шаблона со словарем.
Обновленная функция ReadBlob
выглядит следующим образом:
// So we can access the BindingTemplateSource class
using Microsoft.Azure.WebJobs.Host.Bindings.Path;
[FunctionName("ReadBlob")]
public static async Task<string> ReadBlob(
[ActivityTrigger] JObject eventData,
[Blob("{data.url}", FileAccess.Read)]CloudBlockBlob blob,
ILogger log)
{
// Define the pattern to match
var blobPattern = "myContainer/{name}.{extension}";
// Create a BindingTemplateSource from the pattern string
var patternTemplate = BindingTemplateSource.FromString(blobPattern);
// Use this BindingTemplateSource to create the binding data
// This returns a IReadOnlyDictionary<string, object> with the parameters mapped
var parameters = patternTemplate.CreateBindingData($"{blob.Container.Name}/{blob.Name}");
// Assuming blob path was "myContainer/myBlob.png":
// Parameters are objects so we need to ToString() them
var name = parameters["name"].ToString(); // name == "myBlob"
var extension = parameters["extension"].ToString(); // extension == "png"
if (extension.Equals("txt", StringComparison.OrdinalIgnoreCase))
{ ... }
else if (extension.Equals("png", StringComparison.OrdinalIgnoreCase))
{
// This executes now!
}
else
{ ... }
}
Тогда эта функциональность могла бы быть обернута в пользовательскую привязку, где параметры сопоставляются для вывода привязок к функции, такой как BlobTrigger
, для самого изящного решения, но взломать ее в такую функцию достигает того, что мне нужно для краткосрочной