Skip to content
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

add coroutine excpetion handler #9

Merged
merged 4 commits into from
Sep 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Release

on:
push:
tags:
- '*.*.*'

jobs:
release:
runs-on: ubuntu-latest
environment: deployment

steps:
- uses: actions/checkout@v3
- name: Get tag
id: vars
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v2
with:
dotnet-version: |
3.1.x
5.0.x
6.0.x
- name: Restore cache
uses: actions/cache@v3
with:
path: ~/.nuget/packages
# Look to see if there is a cache hit for the corresponding requirements file
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
restore-keys: |
${{ runner.os }}-nuget
- name: Pack
run: dotnet pack

- name: Publish
run: dotnet nuget push **/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate

- name: Create release
run: |
curl \
-X POST \
-H "Authorization: token $GITHUB_TOKEN" \
https://api.github.com/repos/${{github.repository}}/releases \
-d '{"tag_name": "${{ env.RELEASE_VERSION }}", "name": "${{ env.RELEASE_VERSION }}", "body": "Release of version ${{ env.RELEASE_VERSION }}", "draft": false, "prerelease": false, "generate_release_notes": true}'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_VERSION: ${{ steps.vars.outputs.tag }}
6 changes: 3 additions & 3 deletions Analytics-CSharp/Analytics-CSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<Authors>Segment, Inc</Authors>
<Description>The hassle-free way to add analytics to your C# app.</Description>
<Version>0.3.0</Version>
<Version>1.0.0</Version>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<RepositoryUrl>https://github.com/segmentio/Analytics-CSharp</RepositoryUrl>
<RepositoryType>git</RepositoryType>
Expand All @@ -32,9 +32,9 @@
<Folder Include="Segment\Analytics\Utilities\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Coroutine.NET" Version="0.5.0" />
<PackageReference Include="Coroutine.NET" Version="1.0.0" />
<PackageReference Include="Serialization.NET" Version="0.1.0" />
<PackageReference Include="Sovran.NET" Version="0.4.0" />
<PackageReference Include="Sovran.NET" Version="1.0.0" />
</ItemGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
Expand Down
6 changes: 3 additions & 3 deletions Analytics-CSharp/Segment/Analytics/Analytics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public partial class Analytics : ISubscriber
public Analytics(Configuration configuration)
{
this.configuration = configuration;
analyticsScope = new Scope();
analyticsScope = new Scope(configuration.exceptionHandler);
if (configuration.userSynchronizeDispatcher)
{
IDispatcher dispatcher = new SynchronizeDispatcher();
Expand All @@ -48,8 +48,8 @@ public Analytics(Configuration configuration)
analyticsDispatcher = new Dispatcher(new LimitedConcurrencyLevelTaskScheduler(Environment.ProcessorCount));
}

store = new Store(configuration.userSynchronizeDispatcher);
storage = new Storage(store, configuration.writeKey, configuration.persistentDataPath, fileIODispatcher);
store = new Store(configuration.userSynchronizeDispatcher, configuration.exceptionHandler);
storage = new Storage(store, configuration.writeKey, configuration.persistentDataPath, fileIODispatcher, configuration.exceptionHandler);
timeline = new Timeline();

// Start everything
Expand Down
11 changes: 9 additions & 2 deletions Analytics-CSharp/Segment/Analytics/Configuration.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

using Segment.Concurrent;

namespace Segment.Analytics
{
public class Configuration
Expand All @@ -21,6 +23,8 @@ public class Configuration

public bool userSynchronizeDispatcher { get; }

public ICoroutineExceptionHandler exceptionHandler { get; }

/// <summary>
/// Configuration that analytics can use
/// </summary>
Expand All @@ -38,7 +42,8 @@ public class Configuration
/// <param name="autoAddSegmentDestination">automatically add SegmentDestination plugin, defaults to <c>true</c></param>
/// <param name="userSynchronizeDispatcher">forcing everything to run synchronously, used for unit tests </param>
/// <param name="apiHost">set a default apiHost to which Segment sends events, defaults to <c>api.segment.io/v1</c></param>
/// <param name="cdnHost">et a default cdnHost to which Segment fetches settings, defaults to <c>cdn-settings.segment.com/v1</c></param>
/// <param name="cdnHost">set a default cdnHost to which Segment fetches settings, defaults to <c>cdn-settings.segment.com/v1</c></param>
/// <param name="exceptionHandler">set a an exception handler to handle errors happened in async methods within the analytics scope</param>
public Configuration(string writeKey,
string persistentDataPath,
int flushAt = 20,
Expand All @@ -47,7 +52,8 @@ public Configuration(string writeKey,
bool autoAddSegmentDestination = true,
bool userSynchronizeDispatcher = false,
string apiHost = null,
string cdnHost = null)
string cdnHost = null,
ICoroutineExceptionHandler exceptionHandler = null)
{
this.writeKey = writeKey;
this.persistentDataPath = persistentDataPath;
Expand All @@ -58,6 +64,7 @@ public Configuration(string writeKey,
this.userSynchronizeDispatcher = userSynchronizeDispatcher;
this.apiHost = apiHost;
this.cdnHost = cdnHost;
this.exceptionHandler = exceptionHandler;
}
}

Expand Down
6 changes: 3 additions & 3 deletions Analytics-CSharp/Segment/Analytics/Internal/ForTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ internal Analytics(Configuration configuration,
)
{
this.configuration = configuration;
this.analyticsScope = analyticsScope ?? new Scope();
this.analyticsScope = analyticsScope ?? new Scope(configuration.exceptionHandler);
IDispatcher dispatcher = new SynchronizeDispatcher();
this.fileIODispatcher = fileIODispatcher ?? dispatcher;
this.networkIODispatcher = networkIODispatcher ?? dispatcher;
this.analyticsDispatcher = analyticsDispatcher ?? dispatcher;
this.store = store ?? new Store(true);
this.storage = storage ?? new Storage(this.store, configuration.writeKey, configuration.persistentDataPath, this.fileIODispatcher);
this.store = store ?? new Store(true, configuration.exceptionHandler);
this.storage = storage ?? new Storage(this.store, configuration.writeKey, configuration.persistentDataPath, this.fileIODispatcher, configuration.exceptionHandler);
this.timeline = timeline ?? new Timeline();

Startup(httpClient);
Expand Down
4 changes: 2 additions & 2 deletions Analytics-CSharp/Segment/Analytics/Utilities/Storage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ internal class Storage : ISubscriber

public const long MaxBatchSize = 475_000;

public Storage(Store store, string writeKey, string rootDir, IDispatcher ioDispatcher = default)
public Storage(Store store, string writeKey, string rootDir, IDispatcher ioDispatcher = default, ICoroutineExceptionHandler exceptionHandler = default)
{
_store = store;
_writeKey = writeKey;
_userPrefs = new UserPrefs(rootDir + Path.DirectorySeparatorChar +
"segment.prefs" + Path.DirectorySeparatorChar + writeKey);
"segment.prefs" + Path.DirectorySeparatorChar + writeKey, exceptionHandler);
_storageDirectory = rootDir + Path.DirectorySeparatorChar +
"segment.data" + Path.DirectorySeparatorChar +
writeKey + Path.DirectorySeparatorChar +
Expand Down
4 changes: 2 additions & 2 deletions Analytics-CSharp/Segment/Analytics/Utilities/UserPrefs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class UserPrefs

private readonly IDispatcher _dispatcher;

public UserPrefs(string file)
public UserPrefs(string file, ICoroutineExceptionHandler exceptionHandler = null)
{
cache = new Dictionary<string, object>();
mutex = new object();
Expand All @@ -52,7 +52,7 @@ public UserPrefs(string file)
// uses a new scope for UserPrefs, so interruption does not propagate to analytics scope
// in addition, file I/O in this class are all blocking. need to have its own threads
// to prevent blocking analytics threads
_scope = new Scope();
_scope = new Scope(exceptionHandler);
_dispatcher = new Dispatcher(new LimitedConcurrencyLevelTaskScheduler(Environment.ProcessorCount));
StartLoadFromDisk();
}
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ To get started with the Analytics-CSharp library:
| `defaultSettings` | Default set to `{}`. <br> The settings object used as fallback in case of network failure. |
| `flushAt` | Default set to `20`. <br> The count of events at which Segment flushes events. |
| `flushInterval` | Default set to `30` (seconds). <br> The interval in seconds at which Segment flushes events. |
| `exceptionHandler` | set a an exception handler to handle errors happened in async methods within the analytics scope |

## Tracking Methods

Expand Down
4 changes: 2 additions & 2 deletions Tests/StateTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public SystemTest()
userSynchronizeDispatcher: true,
defaultSettings: _settings
);
_storage = new Mock<Storage>(_store, "123", "tests", new SynchronizeDispatcher());
_storage = new Mock<Storage>(_store, "123", "tests", new SynchronizeDispatcher(), null);
}

[Fact]
Expand Down Expand Up @@ -137,7 +137,7 @@ public UserInfoTest()
autoAddSegmentDestination: false,
userSynchronizeDispatcher: true
);
_storage = new Mock<Storage>(_store, "123", "tests", new SynchronizeDispatcher());
_storage = new Mock<Storage>(_store, "123", "tests", new SynchronizeDispatcher(), null);
}

[Fact]
Expand Down
2 changes: 1 addition & 1 deletion Tests/Utilities/EventPipelineTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public EventPipelineTest()
.Setup(httpclient => httpclient.Upload(It.IsAny<string>()))
.ReturnsAsync(true);

_storage = new Mock<Storage>(new Store(true), "123", "tests", new SynchronizeDispatcher());
_storage = new Mock<Storage>(new Store(true), "123", "tests", new SynchronizeDispatcher(), null);
_analytics = new Analytics(config,
httpClient: _mockHttpClient.Object,
storage: _storage.Object);
Expand Down