Skip to content

Commit

Permalink
Merge pull request #99 from dennisdoomen/Statistics
Browse files Browse the repository at this point in the history
Introduce mechanism for tracking statistics over HTTP
  • Loading branch information
dennisdoomen authored Jul 14, 2017
2 parents 320afe8 + ad708f0 commit f0b7fd6
Show file tree
Hide file tree
Showing 33 changed files with 1,637 additions and 49 deletions.
15 changes: 11 additions & 4 deletions LiquidProjections.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.13
VisualStudioVersion = 15.0.26430.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{27C8B175-6555-4591-87B1-177A2874FEA9}"
ProjectSection(SolutionItems) = preProject
Expand All @@ -18,11 +18,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiquidProjections.Specs", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleHost", "Samples\ExampleHost\ExampleHost.csproj", "{1B10C576-5212-402E-AC19-8CA1547E3F34}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiquidProjections", "Src\LiquidProjections\LiquidProjections.csproj", "{7B47454D-0129-43CB-AED5-27AFAFDB5D7C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiquidProjections", "Src\LiquidProjections\LiquidProjections.csproj", "{7B47454D-0129-43CB-AED5-27AFAFDB5D7C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiquidProjections.Testing", "Src\LiquidProjections.Testing\LiquidProjections.Testing.csproj", "{B4EA7831-8282-4F3A-A057-2DEB59611A68}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiquidProjections.Testing", "Src\LiquidProjections.Testing\LiquidProjections.Testing.csproj", "{B4EA7831-8282-4F3A-A057-2DEB59611A68}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiquidProjections.Abstractions", "Src\LiquidProjections.Abstractions\LiquidProjections.Abstractions.csproj", "{8E38C862-7DC9-4A7E-A2EE-921FFBC7EE2D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiquidProjections.Abstractions", "Src\LiquidProjections.Abstractions\LiquidProjections.Abstractions.csproj", "{8E38C862-7DC9-4A7E-A2EE-921FFBC7EE2D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiquidProjections.Owin", "Src\LiquidProjections.Owin\LiquidProjections.Owin.csproj", "{43C0A9ED-8094-4646-85A4-6EAA03505A20}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -50,6 +52,10 @@ Global
{8E38C862-7DC9-4A7E-A2EE-921FFBC7EE2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E38C862-7DC9-4A7E-A2EE-921FFBC7EE2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E38C862-7DC9-4A7E-A2EE-921FFBC7EE2D}.Release|Any CPU.Build.0 = Release|Any CPU
{43C0A9ED-8094-4646-85A4-6EAA03505A20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{43C0A9ED-8094-4646-85A4-6EAA03505A20}.Debug|Any CPU.Build.0 = Debug|Any CPU
{43C0A9ED-8094-4646-85A4-6EAA03505A20}.Release|Any CPU.ActiveCfg = Release|Any CPU
{43C0A9ED-8094-4646-85A4-6EAA03505A20}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -60,5 +66,6 @@ Global
{7B47454D-0129-43CB-AED5-27AFAFDB5D7C} = {AE89AB5E-BC68-4AA3-9183-A222AC81691C}
{B4EA7831-8282-4F3A-A057-2DEB59611A68} = {AE89AB5E-BC68-4AA3-9183-A222AC81691C}
{8E38C862-7DC9-4A7E-A2EE-921FFBC7EE2D} = {AE89AB5E-BC68-4AA3-9183-A222AC81691C}
{43C0A9ED-8094-4646-85A4-6EAA03505A20} = {AE89AB5E-BC68-4AA3-9183-A222AC81691C}
EndGlobalSection
EndGlobal
2 changes: 1 addition & 1 deletion Samples/ExampleHost/App.config
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
Expand Down
17 changes: 13 additions & 4 deletions Samples/ExampleHost/CountsProjector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@
using System.Collections.Generic;
using System.Linq;
using LiquidProjections.ExampleHost.Events;
using LiquidProjections.Statistics;

namespace LiquidProjections.ExampleHost
{
public class CountsProjector
{
private readonly Dispatcher dispatcher;
private readonly InMemoryDatabase store;
private readonly ProjectionStats stats;
private ExampleProjector<DocumentCountProjection> documentCountProjector;
private ExampleProjector<CountryLookup> countryLookupProjector;

public CountsProjector(Dispatcher dispatcher, InMemoryDatabase store)
public CountsProjector(Dispatcher dispatcher, InMemoryDatabase store, ProjectionStats stats)
{
this.dispatcher = dispatcher;
this.store = store;
this.stats = stats;

BuildCountryProjector();
BuildDocumentProjector();
Expand Down Expand Up @@ -210,8 +213,11 @@ private void BuildDocumentProjector()
period.Status = "Canceled";
});

documentCountProjector =
new ExampleProjector<DocumentCountProjection>(documentMapBuilder, store, countryLookupProjector);
documentCountProjector =
new ExampleProjector<DocumentCountProjection>(documentMapBuilder, store, stats, countryLookupProjector)
{
Id = "DocumentCount"
};
}

private string GetCountryName(Guid countryCode)
Expand All @@ -229,7 +235,10 @@ private void BuildCountryProjector()
.AsCreateOf(anEvent => anEvent.Code)
.Using((country, anEvent) => country.Name = anEvent.Name);

countryLookupProjector = new ExampleProjector<CountryLookup>(countryMapBuilder, store);
countryLookupProjector = new ExampleProjector<CountryLookup>(countryMapBuilder, store, stats)
{
Id = "CountryLookup"
};
}

private static IEnumerable<ValidityPeriod> GetPreviousContiguousValidPeriods(List<ValidityPeriod> allPeriods,
Expand Down
9 changes: 8 additions & 1 deletion Samples/ExampleHost/ExampleHost.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>LiquidProjections.ExampleHost</RootNamespace>
<AssemblyName>LiquidProjections.ExampleHost</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
Expand Down Expand Up @@ -135,11 +135,18 @@
<Project>{8e38c862-7dc9-4a7e-a2ee-921ffbc7ee2d}</Project>
<Name>LiquidProjections.Abstractions</Name>
</ProjectReference>
<ProjectReference Include="..\..\Src\LiquidProjections.Owin\LiquidProjections.Owin.csproj">
<Project>{43c0a9ed-8094-4646-85a4-6eaa03505a20}</Project>
<Name>LiquidProjections.Owin</Name>
</ProjectReference>
<ProjectReference Include="..\..\Src\LiquidProjections\LiquidProjections.csproj">
<Project>{7b47454d-0129-43cb-aed5-27afafdb5d7c}</Project>
<Name>LiquidProjections</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Connected Services\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>
Expand Down
24 changes: 15 additions & 9 deletions Samples/ExampleHost/ExampleProjector.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LiquidProjections.Statistics;

namespace LiquidProjections.ExampleHost
{
Expand All @@ -13,14 +13,16 @@ public class ExampleProjector<TProjection> : IExampleProjector
where TProjection : class, IEntity, new()
{
private readonly InMemoryDatabase store;
private readonly Projector innerProjector;
private readonly ProjectionStats stats;

public ExampleProjector(IEventMapBuilder<TProjection, string, ProjectionContext> mapBuilder, InMemoryDatabase store, params IExampleProjector[] childProjectors)
public ExampleProjector(IEventMapBuilder<TProjection, string, ProjectionContext> mapBuilder, InMemoryDatabase store,
ProjectionStats stats, params IExampleProjector[] childProjectors)
{
this.store = store;
this.stats = stats;
var map = BuildMapFrom(mapBuilder);

innerProjector = new Projector(map, childProjectors.Select(p => p.InnerProjector));
InnerProjector = new Projector(map, childProjectors.Select(p => p.InnerProjector));
}

private IEventMap<ProjectionContext> BuildMapFrom(IEventMapBuilder<TProjection, string, ProjectionContext> mapBuilder)
Expand Down Expand Up @@ -53,16 +55,20 @@ private IEventMap<ProjectionContext> BuildMapFrom(IEventMapBuilder<TProjection,
return mapBuilder.Build();
}

public Task Handle(IReadOnlyList<Transaction> transactions)
public async Task Handle(IReadOnlyList<Transaction> transactions)
{
return innerProjector.Handle(transactions);
await InnerProjector.Handle(transactions);

stats.TrackProgress(Id, transactions.Last().Checkpoint);
}

public Projector InnerProjector => innerProjector;
public Projector InnerProjector { get; }

public string Id { get; set; }
}

public interface IExampleProjector
{
Projector InnerProjector { get; }
}
}
}
12 changes: 10 additions & 2 deletions Samples/ExampleHost/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.IO;
using System.Web.Http;
using System.Web.Http.Dispatcher;
using LiquidProjections.Owin;
using LiquidProjections.Statistics;
using Microsoft.Owin.Hosting;
using Owin;
using TinyIoC;
Expand All @@ -22,10 +24,16 @@ public static void Main(string[] args)

var dispatcher = new Dispatcher(eventStore.Subscribe);

var bootstrapper = new CountsProjector(dispatcher, projectionsStore);
var stats = new ProjectionStats(() => DateTime.UtcNow);

var bootstrapper = new CountsProjector(dispatcher, projectionsStore, stats);

var startOptions = new StartOptions($"http://localhost:9000");
using (WebApp.Start(startOptions, builder => builder.UseControllers(container)))
using (WebApp.Start(startOptions, builder =>
{
builder.UseControllers(container);
builder.UseLiquidProjections(stats);
}))
{
bootstrapper.Start();

Expand Down
8 changes: 4 additions & 4 deletions Samples/ExampleHost/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]
// [assembly: AssemblyVersion("2.1.1.0")]
[assembly: AssemblyVersion("2.1.1.0")]
[assembly: AssemblyFileVersion("2.1.1.0")]

[assembly: AssemblyInformationalVersion("2.0.0+Branch.master.Sha.6e68f840c3303bac97b10c567815a3bfef3184d7")]
[assembly: AssemblyInformationalVersion("2.1.1-Statistics.1+2.Branch.Statistics.Sha.d204fd580c5bb1f85bdcdd4819af6123c7315da8")]
6 changes: 3 additions & 3 deletions Src/LiquidProjections.Abstractions/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@

[assembly: ComVisible(false)]

[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyInformationalVersion("2.0.0+Branch.master.Sha.6e68f840c3303bac97b10c567815a3bfef3184d7")]
[assembly: AssemblyVersion("2.1.1.0")]
[assembly: AssemblyFileVersion("2.1.1.0")]
[assembly: AssemblyInformationalVersion("2.1.1-Statistics.1+2.Branch.Statistics.Sha.d204fd580c5bb1f85bdcdd4819af6123c7315da8")]
26 changes: 26 additions & 0 deletions Src/LiquidProjections.Owin/.nuspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>LiquidProjections.Owin</id>
<version>0.0.0.0</version>
<authors>Dennis Doomen</authors>
<owners>Dennis Doomen</owners>
<projectUrl>https://github.com/liquidprojections/LiquidProjections</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Provides OWIN Middleware to access LiquidProjection over HTTP.</description>
<tags>event-sourcing; projections; ddd; owin; webapi</tags>
<frameworkAssemblies />
<releaseNotes/>
<dependencies>
<group>
<dependency id="LiquidProjections" version="$nugetversion$"/>
<dependency id="Owin" version="1.0.0.0"/>
</group>
</dependencies>
</metadata>
<files>
<file src="..\..\Artifacts\LiquidProjections.Owin.dll" target="lib\net452" />
<file src="..\..\Artifacts\LiquidProjections.Owin.pdb" target="lib\net452" />
<file src="..\..\Artifacts\LiquidProjections.Owin.xml" target="lib\net452" />
</files>
</package>
124 changes: 124 additions & 0 deletions Src/LiquidProjections.Owin/CustomNancyBootstrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using LiquidProjections.Statistics;
using Nancy;
using Nancy.Bootstrapper;
using Nancy.Configuration;
using Nancy.Extensions;
using Nancy.Linker;
using Nancy.Metadata.Modules;
using Nancy.Routing;
using Nancy.Swagger;
using Nancy.Swagger.Modules;
using Nancy.Swagger.Services;
using Nancy.TinyIoc;

namespace LiquidProjections.Owin
{
internal class CustomNancyBootstrapper : DefaultNancyBootstrapper
{
private readonly ProjectionStats stats;

public CustomNancyBootstrapper(ProjectionStats stats)
{
this.stats = stats;
}

protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
{
base.ApplicationStartup(container, pipelines);

SwaggerMetadataProvider.SetInfo(
"LiquidProjections",
Assembly.GetExecutingAssembly().GetName().Version.ToString(),
"Provides statistics about running projectors"
);
}

#if DEBUG

public override void Configure(INancyEnvironment environment)
{
environment.Tracing(enabled: false, displayErrorTraces: true);
base.Configure(environment);
}
#endif

protected override IAssemblyCatalog AssemblyCatalog => new StaticAssemblyCatalog();

protected override ITypeCatalog TypeCatalog => new InternalTypeCatalog(AssemblyCatalog);

protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
container.Register<IResourceLinker>((x, overloads) =>
new ResourceLinker(x.Resolve<IRouteCacheProvider>(),
x.Resolve<IRouteSegmentExtractor>(), x.Resolve<IUriFilter>()));

container.Register<IRegistrations, Registration>("LinkerRegistrations");
container.Register<IRegistrations, SwaggerRegistrations>("SwaggerRegistrations");
container.Register(stats);
}

protected override IEnumerable<ModuleRegistration> Modules =>
new[]
{
new ModuleRegistration(typeof(SwaggerModule)),
new ModuleRegistration(typeof(StatisticsModule))
};
}

internal class StaticAssemblyCatalog : IAssemblyCatalog
{
public IReadOnlyCollection<Assembly> GetAssemblies()
{
return new[]
{
typeof(MetadataModuleRegistrations).Assembly,
typeof(CustomNancyBootstrapper).Assembly,
typeof(DefaultNancyBootstrapper).Assembly
}.Distinct().ToArray();
}
}

/// <summary>
/// Implementation of the <see cref="T:Nancy.ITypeCatalog" /> interface that will find internal types as well.
/// </summary>
internal class InternalTypeCatalog : ITypeCatalog
{
private readonly IAssemblyCatalog assemblyCatalog;
private readonly ConcurrentDictionary<Type, IReadOnlyCollection<Type>> cache;

/// <summary>
/// Initializes a new instance of the <see cref="T:Nancy.DefaultTypeCatalog" /> class.
/// </summary>
/// <param name="assemblyCatalog">An <see cref="T:Nancy.IAssemblyCatalog" /> instanced, used to get the assemblies that types should be resolved from.</param>
public InternalTypeCatalog(IAssemblyCatalog assemblyCatalog)
{
this.assemblyCatalog = assemblyCatalog;
cache = new ConcurrentDictionary<Type, IReadOnlyCollection<Type>>();
}

/// <summary>
/// Gets all types that are assignable to the provided <paramref name="type" />.
/// </summary>
/// <param name="type">The <see cref="T:System.Type" /> that returned types should be assignable to.</param>
/// <param name="strategy">A <see cref="T:Nancy.TypeResolveStrategy" /> that should be used when retrieving types.</param>
/// <returns>An <see cref="T:System.Collections.Generic.IReadOnlyCollection`1" /> of <see cref="T:System.Type" /> instances.</returns>
public IReadOnlyCollection<Type> GetTypesAssignableTo(Type type, TypeResolveStrategy strategy)
{
return cache.GetOrAdd(type, t => GetTypesAssignableTo(type))
.Where(strategy.Invoke).ToArray();
}

private IReadOnlyCollection<Type> GetTypesAssignableTo(Type type)
{
return assemblyCatalog.GetAssemblies()
.SelectMany(assembly => assembly.SafeGetTypes())
.Where(type.IsAssignableFrom)
.Where(t => !t.GetTypeInfo().IsAbstract).ToArray();
}
}
}
Loading

0 comments on commit f0b7fd6

Please sign in to comment.