/// <summary> /// Keeps trying to checkout a guild (with backoff) until either maxTimeout has been hit, /// or a value has been returned that's not Locked. /// </summary> /// <param name="repo">A repo. May not be null.</param> /// <param name="guildId">An id associated with a guild.</param> /// <param name="maxTimeout">The maximum amount of time to spend waiting for this to unlock.</param> /// <param name="recycleResult">A preallocated result that should be returned if passed in.</param> /// <returns>The result.</returns> public static async Task <GuildCheckoutResult> WaitForNotLockedCheckout( this IGuildRepository repo, Snowflake guildId, TimeSpan maxTimeout, GuildCheckoutResult recycleResult = null) { Stopwatch timer = new Stopwatch(); var retVal = recycleResult ?? new GuildCheckoutResult(); TimeSpan nextDelay = TimeSpan.FromMilliseconds(1); timer.Start(); retVal = await repo.Checkout(guildId, retVal); while (retVal.Result == GuildCheckoutResult.ResultType.Locked && timer.Elapsed + nextDelay < maxTimeout) { await Task.Delay(nextDelay); retVal = await repo.Checkout(guildId, retVal); nextDelay *= 1.5; } return(retVal); }
/// <summary> /// Checkout out a <see cref="Guild"/>. /// </summary> /// <param name="guildId">An id representing a guild.</param> /// <param name="recycleResult">A preallocated result that should be returned if passed in.</param> /// <returns>The borrowed guild.</returns> public async Task <GuildCheckoutResult> Checkout(Snowflake guildId, GuildCheckoutResult recycleResult = null) { var retVal = recycleResult ?? new GuildCheckoutResult(); try { string blobName = AzureBlobGuildRepository.GetBlobName(guildId); var blobClient = this.blobContainerClient.GetBlockBlobClient(blobName); // Aquire a lease on the blob var blobLeaseClient = blobClient.GetBlobLeaseClient(); var leaseResult = await blobLeaseClient.AcquireAsync(AzureBlobGuildRepository.BlobLeaseDuration).ConfigureAwait(false); var lease = leaseResult.Value; Guild guild; using (var sourceStream = await blobClient.OpenReadAsync()) using (var streamReader = new StreamReader(sourceStream)) using (var jsonReader = new JsonTextReader(streamReader)) { guild = GuildConverter.FromJToken(guildId, await JObject.ReadFromAsync(jsonReader)); } retVal.ToSuccess(new Borrowed <Guild>( isntance: guild, data: lease, onReturn: this.ReturnGuild)); return(retVal); } catch (RequestFailedException e) { if (e.Status == AzureBlobGuildRepository.NotFoundStatus) { retVal.ToDoesNotExist(); return(retVal); } else if (e.Status == AzureBlobGuildRepository.ConflictStatus && "LeaseAlreadyPresent".Equals(e.ErrorCode, StringComparison.OrdinalIgnoreCase)) { retVal.ToLocked(); return(retVal); } else { throw; } } }
/// <summary> /// Checkout out or create a <see cref="Guild"/> if one does not exist. /// </summary> /// <param name="guildId">An id representing a guild.</param> /// <param name="recycleResult">A preallocated result that should be returned if passed in.</param> /// <returns>The borrowed guild.</returns> public async Task <GuildCheckoutResult> Checkout(Snowflake guildId, GuildCheckoutResult recycleResult = null) { var retVal = recycleResult ?? new GuildCheckoutResult(); try { var sourceStream = new FileStream( FileBasedGuildRepository.GetFilePath(guildId), FileMode.Open, FileAccess.ReadWrite, FileShare.None, bufferSize: 4096, useAsync: true); var streamReader = new StreamReader(sourceStream); var jsonReader = new JsonTextReader(streamReader); var guild = GuildConverter.FromJToken(guildId, await JObject.ReadFromAsync(jsonReader)); retVal.ToSuccess(new Borrowed <Guild>( isntance: guild, data: sourceStream, onReturn: FileBasedGuildRepository.ReturnGuild)); return(retVal); } catch (FileNotFoundException) { retVal.ToDoesNotExist(); return(retVal); } catch (IOException e) { if (e.HResult == FileBasedGuildRepository.LockedFileHRResult) { retVal.ToLocked(); return(retVal); } else { throw; } } }