Skip to content

Commit

Permalink
Merge pull request #24 from marcwittke/hotfix/2.1.2
Browse files Browse the repository at this point in the history
Hotfix/2.1.2
  • Loading branch information
marcwittke committed May 2, 2018
2 parents dceffb8 + d0c2c8a commit 9b47dbd
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 37 deletions.
6 changes: 4 additions & 2 deletions src/Backend.Fx.Bootstrapping/BackendFxApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ public abstract class BackendFxApplication : IDisposable
/// <param name="databaseManager">The database manager for the current application</param>
/// <param name="tenantManager">The tenant manager for the current application</param>
/// <param name="scopeManager">The scope manager for the current application</param>
/// <param name="jobExecutor">The job executor for the current application. If not provided, a default <see cref="Patterns.Jobs.JobExecutor"/> instance is generated.</param>
protected BackendFxApplication(
ICompositionRoot compositionRoot,
IDatabaseManager databaseManager,
ITenantManager tenantManager,
IScopeManager scopeManager)
IScopeManager scopeManager,
IJobExecutor jobExecutor = null)
{
JobExecutor = new JobExecutor(tenantManager, scopeManager);
JobExecutor = jobExecutor ?? new JobExecutor(tenantManager, scopeManager);
CompositionRoot = compositionRoot;
DatabaseManager = databaseManager;
TenantManager = tenantManager;
Expand Down
26 changes: 25 additions & 1 deletion src/Backend.Fx/Exceptions/ClientException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

public class ClientException : Exception
{
public ClientException() : this("Bad Request")
public ClientException()
{}

public ClientException(string message) : base(message)
Expand All @@ -20,5 +20,29 @@ public bool HasErrors()
{
return Errors.Any();
}

public override string Message
{
get
{
if (!string.IsNullOrEmpty(base.Message))
{
return base.Message;
}

if (HasErrors() && Errors.TryGetValue(Errors.GenericErrorKey, out Error[] genericErrors))
{
var errors = genericErrors.Select(err => $"{err.Code}:{err.Message}");
return string.Join(". ", errors);
}

return DefaultMessage;
}
}

protected virtual string DefaultMessage
{
get { return "Bad Request."; }
}
}
}
2 changes: 1 addition & 1 deletion src/Backend.Fx/Exceptions/ExceptionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class ExceptionBuilder<TEx> : IDisposable where TEx : ClientException, ne
private static readonly ILogger Logger = LogManager.Create<ExceptionBuilder<TEx>>();
private readonly TEx clientException = new TEx();

internal ExceptionBuilder()
public ExceptionBuilder()
{ }

public void Add(Error error)
Expand Down
49 changes: 49 additions & 0 deletions src/Backend.Fx/Exceptions/UnauthorizedException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
namespace Backend.Fx.Exceptions
{
using System;

public class UnauthorizedException : ClientException
{
public enum Code
{
AccessDenied,
NotAuthenticated,
AccountLocked
}

public UnauthorizedException()
{ }

public UnauthorizedException(string message) : base(message)
{ }

public UnauthorizedException(string message, Exception innerException) : base(message, innerException)
{ }

public static UnauthorizedException AccessDenied()
{
var exception = new UnauthorizedException();
exception.Errors.Add(new Error(Code.AccessDenied, "Access to this function or data is denied."));
return exception;
}

public static UnauthorizedException AccountLocked()
{
var exception = new UnauthorizedException();
exception.Errors.Add(new Error(Code.AccountLocked, "The identity's user account is locked."));
return exception;
}

public static UnauthorizedException NotAuthenticated()
{
var exception = new UnauthorizedException();
exception.Errors.Add(new Error(Code.NotAuthenticated, "Identity must be authenticated to access this function or data."));
return exception;
}

protected override string DefaultMessage
{
get { return "Unauthorized access."; }
}
}
}
7 changes: 6 additions & 1 deletion src/Backend.Fx/Exceptions/UnprocessableException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

public class UnprocessableException : ClientException
{
public UnprocessableException() : this("The provided arguments could not be processed.")
public UnprocessableException()
{ }

public UnprocessableException(string message) : base(message)
Expand All @@ -17,5 +17,10 @@ public static UnprocessableExceptionBuilder UseBuilder()
{
return new UnprocessableExceptionBuilder();
}

protected override string DefaultMessage
{
get { return "The provided arguments could not be processed."; }
}
}
}
67 changes: 35 additions & 32 deletions src/Backend.Fx/Patterns/Jobs/IJobExecutor.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace Backend.Fx.Patterns.Jobs
{
using System;
using System.Threading;
using System.Threading.Tasks;
using DependencyInjection;
using Environment.Authentication;
Expand Down Expand Up @@ -29,40 +30,42 @@ public JobExecutor(ITenantManager tenantManager, IScopeManager scopeManager)
this.scopeManager = scopeManager;
}

public async Task ExecuteJobAsync<TJob>(int? tenantId = null, int delayInSeconds = 0) where TJob : class, IJob
public virtual void ExecuteJob<TJob>(int? tenantId = null, int delayInSeconds = 0) where TJob : class, IJob
{
await Task.Delay(delayInSeconds * 1000);
await Task.Run(() =>
{
TenantId[] tenants = tenantId == null
? tenantManager.GetTenantIds()
: new[] { new TenantId(tenantId.Value) };
Thread.Sleep(delayInSeconds * 1000);
TenantId[] tenants = tenantId == null
? tenantManager.GetTenantIds()
: new[] { new TenantId(tenantId.Value) };

string jobName = typeof(TJob).Name;
foreach (var tenant in tenants)
{
using (Logger.InfoDuration($"Beginning {jobName} scope", $"{jobName} scope completed"))
{
using (IScope scope = scopeManager.BeginScope(new SystemIdentity(), tenant))
{
scope.BeginUnitOfWork(false);
try
{
scope.GetInstance<TJob>().Execute();
scope.GetInstance<IUnitOfWork>().Complete();
}
catch (Exception ex)
{
Logger.Error(ex, $"Execution of {jobName} failed: {ex.Message}");
}
finally
{
scope.GetInstance<IUnitOfWork>().Dispose();
}
}
}
}
});
string jobName = typeof(TJob).Name;
foreach (var tenant in tenants)
{
using (Logger.InfoDuration($"Beginning {jobName} scope", $"{jobName} scope completed"))
{
using (IScope scope = scopeManager.BeginScope(new SystemIdentity(), tenant))
{
scope.BeginUnitOfWork(false);
try
{
scope.GetInstance<TJob>().Execute();
scope.GetInstance<IUnitOfWork>().Complete();
}
catch (Exception ex)
{
Logger.Error(ex, $"Execution of {jobName} failed: {ex.Message}");
}
finally
{
scope.GetInstance<IUnitOfWork>().Dispose();
}
}
}
}
}

public virtual async Task ExecuteJobAsync<TJob>(int? tenantId = null, int delayInSeconds = 0) where TJob : class, IJob
{
await Task.Run(() => ExecuteJob<TJob>(tenantId, delayInSeconds));
}
}
}

0 comments on commit 9b47dbd

Please sign in to comment.