Skip to content
This repository was archived by the owner on Jan 18, 2022. It is now read-only.

Commit 124fb22

Browse files
authored
Fixed world being disposed multiple times (#952)
* fixing errors when stopping editor application * changelog * pr feedback * adding token cancellation * more feedback * slightly refactoring token lifecycle * using block
1 parent a357768 commit 124fb22

File tree

5 files changed

+76
-14
lines changed

5 files changed

+76
-14
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
- Upgraded the project to be compatible with `2019.1.3f1`.
88

9+
### Fixed
10+
11+
- Fixed a bug where a worker's `World` could get disposed multiple times if you stopped the application inside the Editor while the worker is being created.
12+
913
## `0.2.2` - 2019-05-15
1014

1115
### Breaking Changes
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using System.Threading;
3+
using System.Threading.Tasks;
4+
5+
namespace Improbable.Gdk.Core
6+
{
7+
public static class TaskUtility
8+
{
9+
public static async Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
10+
{
11+
var tcs = new TaskCompletionSource<bool>();
12+
using (cancellationToken.Register(s => ((TaskCompletionSource<bool>) s).TrySetResult(true), tcs))
13+
{
14+
if (task != await Task.WhenAny(task, tcs.Task))
15+
{
16+
throw new OperationCanceledException(cancellationToken);
17+
}
18+
}
19+
20+
return task.Result;
21+
}
22+
}
23+
}

workers/unity/Packages/com.improbable.gdk.core/Utility/TaskUtility.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

workers/unity/Packages/com.improbable.gdk.core/Worker/Worker.cs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Threading;
23
using System.Threading.Tasks;
34
using Improbable.Gdk.ReactiveComponents;
45
using Improbable.Worker.CInterop;
@@ -96,11 +97,13 @@ private static async Task<Worker> TryToConnectAsync(Future<Connection> connectio
9697
ILogDispatcher logger,
9798
Vector3 origin)
9899
{
99-
var connection = await Task.Run(() => connectionFuture.Get());
100-
if (connection.GetConnectionStatusCode() != ConnectionStatusCode.Success)
100+
Connection connection;
101+
using (var tokenSource = new CancellationTokenSource())
101102
{
102-
throw new ConnectionFailedException(GetConnectionFailureReason(connection),
103-
ConnectionErrorReason.CannotEstablishConnection);
103+
Action cancelTask = delegate { tokenSource?.Cancel(); };
104+
Application.quitting += cancelTask;
105+
connection = await Task.Run(() => connectionFuture.Get()).WithCancellation(tokenSource.Token);
106+
Application.quitting -= cancelTask;
104107
}
105108

106109
// A check is needed for the case that play mode is exited before the connection can complete.
@@ -111,6 +114,12 @@ private static async Task<Worker> TryToConnectAsync(Future<Connection> connectio
111114
ConnectionErrorReason.EditorApplicationStopped);
112115
}
113116

117+
if (connection.GetConnectionStatusCode() != ConnectionStatusCode.Success)
118+
{
119+
throw new ConnectionFailedException(GetConnectionFailureReason(connection),
120+
ConnectionErrorReason.CannotEstablishConnection);
121+
}
122+
114123
var worker = new Worker(workerType, connection, logger, origin);
115124
logger.HandleLog(LogType.Log, new LogEvent("Successfully created a worker")
116125
.WithField("WorkerId", worker.WorkerId));
@@ -121,7 +130,7 @@ private static async Task<Worker> TryToConnectAsync(Future<Connection> connectio
121130
/// Connects to the SpatialOS Runtime via the Receptionist service and creates a <see cref="Worker" /> object
122131
/// asynchronously.
123132
/// </summary>
124-
/// <param name="config">
133+
/// <param name="parameters">
125134
/// The <see cref="ReceptionistConfig" /> object stores the configuration needed to connect via the
126135
/// Receptionist Service.
127136
/// </param>
@@ -133,12 +142,13 @@ private static async Task<Worker> TryToConnectAsync(Future<Connection> connectio
133142
/// <see cref="Worker" /> object upon connecting successfully.
134143
/// </returns>
135144
public static async Task<Worker> CreateWorkerAsync(
136-
ReceptionistConfig config,
145+
ReceptionistConfig parameters,
137146
ConnectionParameters connectionParameters,
138-
ILogDispatcher logger, Vector3 origin)
147+
ILogDispatcher logger,
148+
Vector3 origin)
139149
{
140150
using (var connectionFuture =
141-
Connection.ConnectAsync(config.ReceptionistHost, config.ReceptionistPort, config.WorkerId,
151+
Connection.ConnectAsync(parameters.ReceptionistHost, parameters.ReceptionistPort, parameters.WorkerId,
142152
connectionParameters))
143153
{
144154
return await TryToConnectAsync(connectionFuture, connectionParameters.WorkerType, logger, origin);
@@ -149,7 +159,7 @@ public static async Task<Worker> CreateWorkerAsync(
149159
/// Connects to the SpatialOS Runtime via the Locator service and creates a <see cref="Worker" /> object
150160
/// asynchronously.
151161
/// </summary>
152-
/// <param name="config">
162+
/// <param name="parameters">
153163
/// The <see cref="LocatorConfig" /> object stores the configuration needed to connect via the
154164
/// Receptionist Service.
155165
/// </param>
@@ -163,7 +173,8 @@ public static async Task<Worker> CreateWorkerAsync(
163173
public static async Task<Worker> CreateWorkerAsync(
164174
LocatorConfig parameters,
165175
ConnectionParameters connectionParameters,
166-
ILogDispatcher logger, Vector3 origin)
176+
ILogDispatcher logger,
177+
Vector3 origin)
167178
{
168179
using (var locator = new Locator(parameters.LocatorHost, parameters.LocatorParameters))
169180
{
@@ -187,7 +198,7 @@ public static async Task<Worker> CreateWorkerAsync(
187198
/// Connects to the SpatialOS Runtime via the Alpha Locator service and creates a <see cref="Worker" /> object
188199
/// asynchronously.
189200
/// </summary>
190-
/// <param name="config">
201+
/// <param name="parameters">
191202
/// The <see cref="AlphaLocatorConfig" /> object stores the configuration needed to connect via the
192203
/// Receptionist Service.
193204
/// </param>
@@ -201,7 +212,8 @@ public static async Task<Worker> CreateWorkerAsync(
201212
public static async Task<Worker> CreateWorkerAsync(
202213
AlphaLocatorConfig parameters,
203214
ConnectionParameters connectionParameters,
204-
ILogDispatcher logger, Vector3 origin)
215+
ILogDispatcher logger,
216+
Vector3 origin)
205217
{
206218
using (var locator = new AlphaLocator(parameters.LocatorHost, parameters.LocatorParameters))
207219
{
@@ -268,7 +280,11 @@ private void AddCoreSystems()
268280

269281
public void Dispose()
270282
{
271-
World?.Dispose();
283+
if (World != null && World.IsCreated)
284+
{
285+
World.Dispose();
286+
}
287+
272288
World = null;
273289
LogDispatcher?.Dispose();
274290
LogDispatcher = null;

workers/unity/Packages/com.improbable.gdk.core/Worker/WorkerConnector.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Improbable.Worker.CInterop.Alpha;
99
using Unity.Entities;
1010
using UnityEngine;
11+
using UnityEngine.EventSystems;
1112

1213
namespace Improbable.Gdk.Core
1314
{
@@ -118,6 +119,8 @@ await Worker.CreateWorkerAsync(GetAlphaLocatorConfig(workerType), connectionPara
118119
if (!Application.isPlaying)
119120
{
120121
Dispose();
122+
throw new ConnectionFailedException("Editor application stopped",
123+
ConnectionErrorReason.EditorApplicationStopped);
121124
}
122125

123126
HandleWorkerConnectionEstablished();
@@ -368,6 +371,11 @@ private static async Task<Worker> ConnectWithRetries(ConnectionDelegate connecti
368371
}
369372
catch (ConnectionFailedException e)
370373
{
374+
if (e.Reason == ConnectionErrorReason.EditorApplicationStopped)
375+
{
376+
throw;
377+
}
378+
371379
--remainingAttempts;
372380
logger.HandleLog(LogType.Error,
373381
new LogEvent($"Failed attempt {maxAttempts - remainingAttempts} to create worker")
@@ -405,7 +413,7 @@ public virtual void Dispose()
405413
{
406414
Worker?.Dispose();
407415
Worker = null;
408-
Destroy(this);
416+
UnityObjectDestroyer.Destroy(this);
409417
}
410418
}
411419
}

0 commit comments

Comments
 (0)