Skip to content

Commit bba511d

Browse files
authored
add coroutine excpetion handler (#9)
* add coroutine exception handler * bug fix * add auto release * update version
1 parent 307de9d commit bba511d

File tree

10 files changed

+74
-18
lines changed

10 files changed

+74
-18
lines changed

.github/workflows/release.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- '*.*.*'
7+
8+
jobs:
9+
release:
10+
runs-on: ubuntu-latest
11+
environment: deployment
12+
13+
steps:
14+
- uses: actions/checkout@v3
15+
- name: Get tag
16+
id: vars
17+
run: echo ::set-output name=tag::${GITHUB_REF#refs/*/}
18+
- name: Setup .NET Core SDK
19+
uses: actions/setup-dotnet@v2
20+
with:
21+
dotnet-version: |
22+
3.1.x
23+
5.0.x
24+
6.0.x
25+
- name: Restore cache
26+
uses: actions/cache@v3
27+
with:
28+
path: ~/.nuget/packages
29+
# Look to see if there is a cache hit for the corresponding requirements file
30+
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
31+
restore-keys: |
32+
${{ runner.os }}-nuget
33+
- name: Pack
34+
run: dotnet pack
35+
36+
- name: Publish
37+
run: dotnet nuget push **/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }} --skip-duplicate
38+
39+
- name: Create release
40+
run: |
41+
curl \
42+
-X POST \
43+
-H "Authorization: token $GITHUB_TOKEN" \
44+
https://api.github.com/repos/${{github.repository}}/releases \
45+
-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}'
46+
env:
47+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48+
RELEASE_VERSION: ${{ steps.vars.outputs.tag }}

Analytics-CSharp/Analytics-CSharp.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
<Authors>Segment, Inc</Authors>
1212
<Description>The hassle-free way to add analytics to your C# app.</Description>
13-
<Version>0.3.0</Version>
13+
<Version>1.0.0</Version>
1414
<PackageLicenseExpression>MIT</PackageLicenseExpression>
1515
<RepositoryUrl>https://github.com/segmentio/Analytics-CSharp</RepositoryUrl>
1616
<RepositoryType>git</RepositoryType>
@@ -32,9 +32,9 @@
3232
<Folder Include="Segment\Analytics\Utilities\" />
3333
</ItemGroup>
3434
<ItemGroup>
35-
<PackageReference Include="Coroutine.NET" Version="0.5.0" />
35+
<PackageReference Include="Coroutine.NET" Version="1.0.0" />
3636
<PackageReference Include="Serialization.NET" Version="0.1.0" />
37-
<PackageReference Include="Sovran.NET" Version="0.4.0" />
37+
<PackageReference Include="Sovran.NET" Version="1.0.0" />
3838
</ItemGroup>
3939
<ItemGroup>
4040
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">

Analytics-CSharp/Segment/Analytics/Analytics.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public partial class Analytics : ISubscriber
3333
public Analytics(Configuration configuration)
3434
{
3535
this.configuration = configuration;
36-
analyticsScope = new Scope();
36+
analyticsScope = new Scope(configuration.exceptionHandler);
3737
if (configuration.userSynchronizeDispatcher)
3838
{
3939
IDispatcher dispatcher = new SynchronizeDispatcher();
@@ -48,8 +48,8 @@ public Analytics(Configuration configuration)
4848
analyticsDispatcher = new Dispatcher(new LimitedConcurrencyLevelTaskScheduler(Environment.ProcessorCount));
4949
}
5050

51-
store = new Store(configuration.userSynchronizeDispatcher);
52-
storage = new Storage(store, configuration.writeKey, configuration.persistentDataPath, fileIODispatcher);
51+
store = new Store(configuration.userSynchronizeDispatcher, configuration.exceptionHandler);
52+
storage = new Storage(store, configuration.writeKey, configuration.persistentDataPath, fileIODispatcher, configuration.exceptionHandler);
5353
timeline = new Timeline();
5454

5555
// Start everything

Analytics-CSharp/Segment/Analytics/Configuration.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11

2+
using Segment.Concurrent;
3+
24
namespace Segment.Analytics
35
{
46
public class Configuration
@@ -21,6 +23,8 @@ public class Configuration
2123

2224
public bool userSynchronizeDispatcher { get; }
2325

26+
public ICoroutineExceptionHandler exceptionHandler { get; }
27+
2428
/// <summary>
2529
/// Configuration that analytics can use
2630
/// </summary>
@@ -38,7 +42,8 @@ public class Configuration
3842
/// <param name="autoAddSegmentDestination">automatically add SegmentDestination plugin, defaults to <c>true</c></param>
3943
/// <param name="userSynchronizeDispatcher">forcing everything to run synchronously, used for unit tests </param>
4044
/// <param name="apiHost">set a default apiHost to which Segment sends events, defaults to <c>api.segment.io/v1</c></param>
41-
/// <param name="cdnHost">et a default cdnHost to which Segment fetches settings, defaults to <c>cdn-settings.segment.com/v1</c></param>
45+
/// <param name="cdnHost">set a default cdnHost to which Segment fetches settings, defaults to <c>cdn-settings.segment.com/v1</c></param>
46+
/// <param name="exceptionHandler">set a an exception handler to handle errors happened in async methods within the analytics scope</param>
4247
public Configuration(string writeKey,
4348
string persistentDataPath,
4449
int flushAt = 20,
@@ -47,7 +52,8 @@ public Configuration(string writeKey,
4752
bool autoAddSegmentDestination = true,
4853
bool userSynchronizeDispatcher = false,
4954
string apiHost = null,
50-
string cdnHost = null)
55+
string cdnHost = null,
56+
ICoroutineExceptionHandler exceptionHandler = null)
5157
{
5258
this.writeKey = writeKey;
5359
this.persistentDataPath = persistentDataPath;
@@ -58,6 +64,7 @@ public Configuration(string writeKey,
5864
this.userSynchronizeDispatcher = userSynchronizeDispatcher;
5965
this.apiHost = apiHost;
6066
this.cdnHost = cdnHost;
67+
this.exceptionHandler = exceptionHandler;
6168
}
6269
}
6370

Analytics-CSharp/Segment/Analytics/Internal/ForTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ internal Analytics(Configuration configuration,
2727
)
2828
{
2929
this.configuration = configuration;
30-
this.analyticsScope = analyticsScope ?? new Scope();
30+
this.analyticsScope = analyticsScope ?? new Scope(configuration.exceptionHandler);
3131
IDispatcher dispatcher = new SynchronizeDispatcher();
3232
this.fileIODispatcher = fileIODispatcher ?? dispatcher;
3333
this.networkIODispatcher = networkIODispatcher ?? dispatcher;
3434
this.analyticsDispatcher = analyticsDispatcher ?? dispatcher;
35-
this.store = store ?? new Store(true);
36-
this.storage = storage ?? new Storage(this.store, configuration.writeKey, configuration.persistentDataPath, this.fileIODispatcher);
35+
this.store = store ?? new Store(true, configuration.exceptionHandler);
36+
this.storage = storage ?? new Storage(this.store, configuration.writeKey, configuration.persistentDataPath, this.fileIODispatcher, configuration.exceptionHandler);
3737
this.timeline = timeline ?? new Timeline();
3838

3939
Startup(httpClient);

Analytics-CSharp/Segment/Analytics/Utilities/Storage.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ internal class Storage : ISubscriber
2525

2626
public const long MaxBatchSize = 475_000;
2727

28-
public Storage(Store store, string writeKey, string rootDir, IDispatcher ioDispatcher = default)
28+
public Storage(Store store, string writeKey, string rootDir, IDispatcher ioDispatcher = default, ICoroutineExceptionHandler exceptionHandler = default)
2929
{
3030
_store = store;
3131
_writeKey = writeKey;
3232
_userPrefs = new UserPrefs(rootDir + Path.DirectorySeparatorChar +
33-
"segment.prefs" + Path.DirectorySeparatorChar + writeKey);
33+
"segment.prefs" + Path.DirectorySeparatorChar + writeKey, exceptionHandler);
3434
_storageDirectory = rootDir + Path.DirectorySeparatorChar +
3535
"segment.data" + Path.DirectorySeparatorChar +
3636
writeKey + Path.DirectorySeparatorChar +

Analytics-CSharp/Segment/Analytics/Utilities/UserPrefs.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class UserPrefs
3737

3838
private readonly IDispatcher _dispatcher;
3939

40-
public UserPrefs(string file)
40+
public UserPrefs(string file, ICoroutineExceptionHandler exceptionHandler = null)
4141
{
4242
cache = new Dictionary<string, object>();
4343
mutex = new object();
@@ -52,7 +52,7 @@ public UserPrefs(string file)
5252
// uses a new scope for UserPrefs, so interruption does not propagate to analytics scope
5353
// in addition, file I/O in this class are all blocking. need to have its own threads
5454
// to prevent blocking analytics threads
55-
_scope = new Scope();
55+
_scope = new Scope(exceptionHandler);
5656
_dispatcher = new Dispatcher(new LimitedConcurrencyLevelTaskScheduler(Environment.ProcessorCount));
5757
StartLoadFromDisk();
5858
}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ To get started with the Analytics-CSharp library:
4040
| `defaultSettings` | Default set to `{}`. <br> The settings object used as fallback in case of network failure. |
4141
| `flushAt` | Default set to `20`. <br> The count of events at which Segment flushes events. |
4242
| `flushInterval` | Default set to `30` (seconds). <br> The interval in seconds at which Segment flushes events. |
43+
| `exceptionHandler` | set a an exception handler to handle errors happened in async methods within the analytics scope |
4344
4445
## Tracking Methods
4546

Tests/StateTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public SystemTest()
3737
userSynchronizeDispatcher: true,
3838
defaultSettings: _settings
3939
);
40-
_storage = new Mock<Storage>(_store, "123", "tests", new SynchronizeDispatcher());
40+
_storage = new Mock<Storage>(_store, "123", "tests", new SynchronizeDispatcher(), null);
4141
}
4242

4343
[Fact]
@@ -137,7 +137,7 @@ public UserInfoTest()
137137
autoAddSegmentDestination: false,
138138
userSynchronizeDispatcher: true
139139
);
140-
_storage = new Mock<Storage>(_store, "123", "tests", new SynchronizeDispatcher());
140+
_storage = new Mock<Storage>(_store, "123", "tests", new SynchronizeDispatcher(), null);
141141
}
142142

143143
[Fact]

Tests/Utilities/EventPipelineTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public EventPipelineTest()
4545
.Setup(httpclient => httpclient.Upload(It.IsAny<string>()))
4646
.ReturnsAsync(true);
4747

48-
_storage = new Mock<Storage>(new Store(true), "123", "tests", new SynchronizeDispatcher());
48+
_storage = new Mock<Storage>(new Store(true), "123", "tests", new SynchronizeDispatcher(), null);
4949
_analytics = new Analytics(config,
5050
httpClient: _mockHttpClient.Object,
5151
storage: _storage.Object);

0 commit comments

Comments
 (0)