-
Notifications
You must be signed in to change notification settings - Fork 452
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CosmosDB Trigger support #1677
CosmosDB Trigger support #1677
Conversation
@ealsur, |
Thank you! Will take a look ASAP! I've flagged your PR in the extensions repo so we can get a full CI build. Once that is merged, I'll push the new package to the MyGet feed to allow the CI tests to run as expected here. |
|
||
if (!string.IsNullOrEmpty(leaseCollectionName)) | ||
{ | ||
attributeTrigger.LeaseCollectionName = leaseCollectionName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how does this work if not all of these lease properties are set?
Also, it might be preferable to bundle all these lease properties in one object, i.e.
{
"type": "documentDbTrigger",
"connection": ...
"lease": {
"collection": ...,
"database": ...,
"connection": ...,
"options": { ... }
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mamaso By default, if no lease properties are set, the Lease database is the same as the databaseName
attribute, the Lease colletion defaults to "leases" and the connection string is the same as the connection
attribute. So it uses the same service, same database but different collection. We are also checking that an infinite loop is not created where both collections are the same.
I will rework the properties of the leases in a nested object in the next commit 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes look good! Just a question about the package version, as that may be problematic.
<Reference Include="Microsoft.Azure.Documents.ChangeFeedProcessor, Version=1.14.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | ||
<HintPath>..\..\packages\Microsoft.Azure.DocumentDB.ChangeFeedProcessor.1.0.0\lib\net45\Microsoft.Azure.Documents.ChangeFeedProcessor.dll</HintPath> | ||
</Reference> | ||
<Reference Include="Microsoft.Azure.Documents.Client, Version=1.13.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the document client package version update required? This would change the version customers get with the `#r "Microsoft.Azure.Documents.Client" directive
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fabiocav Yes. The Change Feed API support within the SDK was introduced in version 1.13.1, that's the minimum version required and the one we are using, basically the restriction is >= 1.13.1 for Change Feed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fabiocav -- the version change is why we held off on getting this into Extensions in the last release. Ultimately, we'll need to move it forward but need to make sure the redirect is updated. There shouldn't be any breaking changes -- but we'll need to monitor the rollout to see if we get any error spikes.
using System; | ||
public static void Run(IReadOnlyList<Document> input) | ||
{ | ||
Console.WriteLine("Documents modified " + input.Count); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Console.WriteLine
doesn't work from a function -- add a parameter ILogger logger
and do a logger.LogInformation("")
instead. That'll send the log to the file logs, App Inisights, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is TraceWriter
ok too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, either works. ILogger
is our newer logger.
<Reference Include="Microsoft.Azure.Documents.ChangeFeedProcessor, Version=1.14.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> | ||
<HintPath>..\..\packages\Microsoft.Azure.DocumentDB.ChangeFeedProcessor.1.0.0\lib\net45\Microsoft.Azure.Documents.ChangeFeedProcessor.dll</HintPath> | ||
</Reference> | ||
<Reference Include="Microsoft.Azure.Documents.Client, Version=1.13.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fabiocav -- the version change is why we held off on getting this into Extensions in the last release. Ultimately, we'll need to move it forward but need to make sure the redirect is updated. There shouldn't be any breaking changes -- but we'll need to monitor the rollout to see if we get any error spikes.
Config.UseDocumentDB(); | ||
DocumentDBConfiguration documentDBConfiguration = new DocumentDBConfiguration(); | ||
|
||
JObject configSection = (JObject)Metadata.GetValue("documentDB", StringComparison.OrdinalIgnoreCase); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're getting into a little of the weirdness of the "CosmosDB" vs "DocumentDB" naming conventions here. This global host.json setting isn't strictly required, is it? The lease options can be set in function.json for each function, if needed. I wonder if we just leave this off to keep things simpler and we can always re-add it in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We were talking with Paul to do a renaming sometime in the future to CosmosDB in everything, but it would be a breaking change for current functions.
I could not make the Lease Options work on the function level. Mainly because, even if I parse it correctly, I cannot pass it to the Attribute because it's not a basic Type, so it doesn't work in:
[CosmosDBTrigger("ItemDb", "ItemCollection", LeaseOptions= new LeaseOptions(...))]
That is why I put it on the global host.json
level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah makes sense -- let's go with this.
CosmosDBTriggerAttribute attributeTrigger = new CosmosDBTriggerAttribute(databaseName, collectionName); | ||
attributeTrigger.ConnectionString = connection; | ||
|
||
JObject leasesConfiguration = Context.GetMetadataValue<JObject>("lease"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know @mamaso recommended we bundle these into a single object, but I seem to recall that the best approach is to have the properties match 1:1 with the attribute in extensions. Eventually, that'll let you remove this code completely and we'll be able to auto-map them. If you change the shape of the metadata (as compared to the attribute), that mapping is harder.
@MikeStall may have more input here.
{ | ||
attribute = new DocumentDBAttribute(databaseName, collectionName); | ||
CosmosDBTriggerAttribute attributeTrigger = new CosmosDBTriggerAttribute(databaseName, collectionName); | ||
attributeTrigger.ConnectionString = connection; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed the difference in this name -- we should change this to ConnectionStringSetting
. I think we're a little inconsistent with the naming, but we decided at some point that using Setting
here made it more clear that it wasn't an actual connection string, but rather an app setting that points to a connection string.
Same with LeaseConnectionStringSetting
(anything with the [AppSetting]
attribute, really).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in next commit
attributeTrigger.LeaseConnectionString = leaseConnectionString.Value<string>(); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you also add support for LeaseOptions
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could not make the Lease Options work on the function level. Mainly because, even if I parse it correctly, I cannot pass it to the Attribute because it's not a basic Type, so it doesn't work in:
[CosmosDBTrigger("ItemDb", "ItemCollection", LeaseOptions= new LeaseOptions(...))]
@@ -159,6 +162,56 @@ public virtual void Dispose() | |||
Host.Stop(); | |||
Host.Dispose(); | |||
ServiceBusQueueClient.Close(); | |||
if (DocumentClient != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to do DocumentClient?.Dispose()
here. Saves a few lines :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I forget sometimes that I can use C# 6 here 😄
@@ -77,6 +78,8 @@ protected EndToEndTestFixture(string rootPath, string testId) | |||
|
|||
public Microsoft.ServiceBus.Messaging.QueueClient ServiceBusQueueClient { get; private set; } | |||
|
|||
public Documents.Client.DocumentClient DocumentClient { get; private set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add usings for Microsoft.Documents
/Microsoft.Documents.Client
so this (and some other lines) is a little shorter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in next commit
// "AzureWebJobsDocumentDBConnectionString" -- the connection string to the account | ||
await Fixture.InitializeDocumentClient(); | ||
bool collectionsCreated = await Fixture.CreateDocumentCollections(); | ||
var resultBlob = Fixture.TestOutputContainer.GetBlockBlobReference("completed"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: just to avoid confusion -- can you name this "cosmosdbtriggere2e-completed"? I know we use "completed" for some others, but it's nicer if it's clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in next commit
Starting the CosmosDB trigger integration following PR: Azure/azure-webjobs-sdk-extensions#244 to integrate with Azure Functions Script Host.
Working on adding E2E tests.