-
Notifications
You must be signed in to change notification settings - Fork 459
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Metrics Collector: Fix adoption stats (#5190)
We removed the test specific logic from the metrics collector. In doing so, this removed a get twin call that was relied on for gauging usage stats. The solution is to recreate the `ModuleClient` (after product info and potentially all other fields are set) even in the Log Analytics code path. This change needs some synchronization as to not interfere with metrics potentially being published from the `IotMessage` metrics upload path (which also uses `ModuleClient`). To achieve this synchronization, I chose to create a wrapper around the `ModuleClient` which serves as the shared reference across multiple `Tasks`. Multiple of these `Tasks` might use the `ModuleClient`. One `Task` could be recreating it while the other could be attempting to publish messages. In order to achieve synchronization I chose to use a `SemaphoreSlim` because I needed some async lock. I ran into some issues when attempting to recreate the `ModuleClient`. 1. If messages tried to be published too quickly, the initial message send would hang. 2. When calling `CloseAsync()` the SDK threw an exception. (SDK bug imo) I managed to resolve these issues by not calling `CloseAsync()` and waiting 1 minute to publish messages. I confirmed in `EdgeHub` logs that multiple connections did not exist.
- Loading branch information
1 parent
bc5ebf1
commit 057da6a
Showing
9 changed files
with
149 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.Azure.Devices.Client; | ||
using Microsoft.Azure.Devices.Edge.Util; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Microsoft.Azure.Devices.Edge.Azure.Monitor | ||
{ | ||
|
||
public class ModuleClientWrapper : IDisposable | ||
{ | ||
ModuleClient inner; | ||
ITransportSettings[] transportSettings; | ||
SemaphoreSlim moduleClientLock; | ||
|
||
public ModuleClientWrapper(ModuleClient moduleClient, ITransportSettings[] transportSettings, SemaphoreSlim moduleClientLock) | ||
{ | ||
this.inner = Preconditions.CheckNotNull(moduleClient); | ||
this.transportSettings = Preconditions.CheckNotNull(transportSettings); | ||
this.moduleClientLock = Preconditions.CheckNotNull(moduleClientLock); | ||
} | ||
|
||
public static async Task<ModuleClientWrapper> BuildModuleClientWrapperAsync(ITransportSettings[] transportSettings) | ||
{ | ||
SemaphoreSlim moduleClientLock = new SemaphoreSlim(1, 1); | ||
|
||
ModuleClient moduleClient = await ModuleClient.CreateFromEnvironmentAsync(transportSettings); | ||
moduleClient.ProductInfo = Constants.ProductInfo; | ||
await moduleClient.OpenAsync(); | ||
|
||
return new ModuleClientWrapper(moduleClient, transportSettings, moduleClientLock); | ||
} | ||
|
||
public async Task RecreateClientAsync() | ||
{ | ||
await this.moduleClientLock.WaitAsync(); | ||
|
||
try | ||
{ | ||
this.inner.Dispose(); | ||
this.inner = await ModuleClient.CreateFromEnvironmentAsync(this.transportSettings); | ||
this.inner.ProductInfo = Constants.ProductInfo; | ||
await this.inner.OpenAsync(); | ||
|
||
LoggerUtil.Writer.LogInformation("Closed and re-established connection to IoT Hub"); | ||
} | ||
catch (Exception e) | ||
{ | ||
LoggerUtil.Writer.LogWarning($"Failed closing and re-establishing connection to IoT Hub: {e.ToString()}"); | ||
} | ||
|
||
this.moduleClientLock.Release(); | ||
} | ||
|
||
public async Task SendMessage(string outputName, Message message) | ||
{ | ||
await this.moduleClientLock.WaitAsync(); | ||
|
||
try | ||
{ | ||
await this.inner.SendEventAsync(outputName, message); | ||
} | ||
catch (Exception e) | ||
{ | ||
LoggerUtil.Writer.LogError($"Failed sending metrics as IoT message: {e.ToString()}"); | ||
} | ||
|
||
this.moduleClientLock.Release(); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
this.inner.Dispose(); | ||
this.moduleClientLock.Dispose(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.