Azure-Functions
Azure-Functions copied to clipboard
Enhancement: Add Scheduled Queue Messages to Service Bus Binding Documentation
From @graham-sportsmgmt on August 22, 2017 16:34
The documentation doesn't mention how we can set the ScheduledEnqueueTimeUtc parameter on an output binding for a Service Bus queue (especially for node.js please)
In at least two other issues it has been mentioned that this is possible, but (a) it still needs some more details to figure out how to send this properly, and (b) it would be REALLY nice to have that in the official docs.
https://github.com/Azure/azure-webjobs-sdk-script/issues/1465 https://github.com/Azure/Azure-Functions/issues/169
At least with C# & Node.js (and why not in F#) the Service Bus queue output already supports this e.g. if you create and put multiple messages e.g. to IAsyncCollector<T> or create out BrokeredMessage. Within your outgoing message(s) you can control the scheduled enqueuing time:
outgoingMessage.ScheduledEnqueueTimeUtc = DateTimeOffset.UtcNow.AddSeconds(10)
I have tried adding this to my function, but it just puts everything into the message and submits it immediately:
queueTime = new Date(Date.now() + 30000).toUTCString();
context.log('current time is ' + new Date().toUTCString() );
context.log('queueTime is ' + queueTime);
context.bindings.queueOutput = {
"message": req.body,
"ScheduledEnqueueTimeUtc": queueTime
}
context.res = {
"status": 200,
"body": {
"message": "Successfully sent message to queue"
}
};
context.done();
Copied from original issue: Azure/azure-webjobs-sdk-script#1813
Thanks, could you please post the correct method of doing this in nodejs in the meantime while the docs are updated?
@christopheranderson Could you provide examples in JavaScript?
@lindydonna, I would advise against supporting this right now because the implications on how Scheduled
and Deferred
messages,
- Are subsequently consumed by ServiceBus-Trigerred Functions, and
- Cause over-scaling.
Issue with Scheduled
messages in ServiceBus-Triggered Functions
When customers create Scheduled
messages on their Service Bus, the logical next step is to create a ServiceBus-Triggered Function that is listening on that ServiceBus. Customer will assume that the Function will be triggered when the Scheduled
message hits its maturity time. This is not how it works in our scaling logic right now and is a known issue.
To summarize the problem, ServiceBus does not provide an API to detect the first Scheduled
message in the queue. We are only able to peek the first message, which could be an Active
, Scheduled
or Deferred
message. In order to determine when to activate the host process or scale out on only Scheduled
message types, we need to:
- Call ServiceBus API to peek the first message that could be of any type.
- Repeatly call peek to iterate down the queue until we find the expected message type.
If the first Scheduled
message is at position 1005 in the queue, we will have to peek 1005 times. This is highly inefficient and we are blocked on this until ServiceBus can provide an efficient API, e.g. PeekAsync(MessageType.Scheduled)
. In the current implementation, we are only able to peek the first message and make activation and scale decisions based on that. Hence, a Function could be triggered regardless of whether its first message is a Scheduled
message or not.
Note: This is the last known state of the ServiceBus API the last time we checked with ServiceBus team a couple of months ago.
Issue with Scheduled
messages in Over-Scaling
Additionally, the current implementation in our scaling code is actually suffering from over-scaling in ServiceBus with mixed-mode messages because if the first message is a Scheduled
message for 30-days in the future, we will keep scaling instances because that message's enqueue time keeps aging and we assume that we need to scale.
Is there a recommended workaround for this? We need to schedule a Function to run at non-regular intervals in the future. Specifically, our customers schedule activities/events and we need to trigger an automated e-mail that goes out 24 hours before the activity/event starts. This is the first of many scheduled events that we will be processing in our SaaS app.
It looks like Azure Scheduler can submit Service Bus Messages in the future, that would seem to be the best way to have a Function Trigger on a Service Bus without loading new messages into the Queue. If that would work, could we possibly get an Azure Function output binding for Azure Scheduler so we don't have to develop a custom REST API Function just to submit future Function jobs?
Edit - I just installed Azure Scheduler into my Portal and it doesn't look like the right solution for hundreds of finely grained events, it's more suited to fewer and recurring events. Is it fair to call this "microscheduling"?
Just curious if there are any updates on this, or even potential workarounds. Our users are starting to give us even more requirements that really need this sort of functionality, and it's about to become critical.
What if we were to just use one queue for scheduled tasks and when they reach maturity we pop them into the execution queue? Would that at least get us past the issue above?
@tohling Just to check if I understand your answer correctly: you don't want to document this feature (or make it work to begin with) for Node.js functions, because handling scheduled messages is not possible for ServiceBus queue triggered messages due to the scaling logic in Azure Functions.
I assume this would only apply to Consumption plans, since they have automatic scaling? A dedicated service plan has no scaling related to triggering functions, only to the cpu/memory of the app service plan (for as far as I know, of course)
Moreover, working from that assumption, I tested this myself. My azure function (running on a dedicated service plan) respects the scheduledEnqueueTimeUtc property, triggering the exact second the property allows it. In other words, it seems to work fine :) However, this does require me to use the Node.js SDK to actually enqueue the message with that broker property (or use an external source which does understand how to set the properties natively).
Either way, it would be great if this functionality could be added and documented, albeit with the note that scheduling is not yet respected by functions running on consumption plans.
@itilitymaarten the scaling logic is agnostic of the language type being used for the Function, so this limitation affects all Functions in the Consumption Plan regardless of the language of choice.
You are correct in that for App Service Plan, customers may choose to scale based on CPU/memory so they can be use those as metrics for scaling. And yes, you may set the ScheduledEnqueueTimeUtc yourself.
@lindydonna @graham-sportsmgmt I've found a workaround that mostly works. You basically have to initiate and call the azure-sb
library from within your function and not use the output bindings. I haven't seen major scaling issues as stated in the issue but we haven't been pushing much yet either. Here is an example:
const azure = require('azure-sb');
const moment = require('moment');
// Note that sb requires dates in this specific string format from my testing.
const scheduled_time = moment().utc().add(5, 'm').format('M/D/YYYY H:mm:ss A');
const msg =
{
body: "Testing",
brokerProperties: {
ScheduledEnqueueTimeUtc: scheduled_time
}
};
const sb = azure.createServiceBusService(process.env.SERVICE_BUS_CONNECTION_STRING);
sb.sendQueueMessage("my_queue_name", msg, function (err) {
if (err) {
console.log('Failed Tx: ', err);
} else {
console.log('Sent ' + msg);
}
});
Is it possible to add custom properties to c# output binding to servicebus?
Any response to @alexgman's question? also looking for this.
Are the problems mentioned by @tohling still relevent? Are they relevent in Azure Functions V2 and above? In my sender Azure Function, I'm using custom bind-out using the package "@azure/service-bus" Node.js and I had no issues while testing. I haven't noticed over-scaling issues, and the reciever (Service Bus triggered Azure Function) gets triggered pretty mcuh on the scheduled time.
After reading this thread, we have stopped a major release of a product that leverages message scheduling in Service Bus queues using Azure Functions. Any updates on this thread?
The custom binding we use for scheduling messages in Azure Service Bus is similar to what is here https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples/javascript/scheduledMessages.js
@lindydonna @graham-sportsmgmt I've found a workaround that mostly works. You basically have to initiate and call the
azure-sb
library from within your function and not use the output bindings. I haven't seen major scaling issues as stated in the issue but we haven't been pushing much yet either. Here is an example:const azure = require('azure-sb'); const moment = require('moment'); // Note that sb requires dates in this specific string format from my testing. const scheduled_time = moment().utc().add(5, 'm').format('M/D/YYYY H:mm:ss A'); const msg = { body: "Testing", brokerProperties: { ScheduledEnqueueTimeUtc: scheduled_time } }; const sb = azure.createServiceBusService(process.env.SERVICE_BUS_CONNECTION_STRING); sb.sendQueueMessage("my_queue_name", msg, function (err) { if (err) { console.log('Failed Tx: ', err); } else { console.log('Sent ' + msg); } });
Hi,
This method works very well, but the brokerProperties are very limited. I need to define the ContentType system property but it isn't include que the azure-sb library. 👎
=> https://github.com/Azure/azure-sdk-for-node/blob/fa35b874c212ed71a56f8093ca8e1d959f661cfb/lib/services/serviceBus/lib/servicebusservice.js
- @param {string} [message.brokerProperties.CorrelationId] The message's correlation identifier.
- @param {string} [message.brokerProperties.SessionId] The session identifier.
- @param {string} [message.brokerProperties.MessageId] The message's identifier.
- @param {string} [message.brokerProperties.Label] The message's label.
- @param {string} [message.brokerProperties.ReplyTo] The message's reply to.
- @param {string} [message.brokerProperties.TimeToLive] The message's time to live.
- @param {string} [message.brokerProperties.To] The message's to.
- @param {string} [message.brokerProperties.ScheduledEnqueueTimeUtc] The message's scheduled enqueue time in UTC.
- @param {string} [message.brokerProperties.ReplyToSessionId] The message's reply to session identifier.