diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/client/Program.cs b/client/Program.cs new file mode 100644 index 0000000..da35bfc --- /dev/null +++ b/client/Program.cs @@ -0,0 +1,20 @@ +var tenantIds = Enumerable.Range(1, 1000).Select(x => Guid.NewGuid()).ToArray(); +var httpClient = new HttpClient(); + +while (true) +{ + Console.Write("Tenant: "); + if (int.TryParse(Console.ReadLine(), out var tenantNumber)) + { + var tenant = tenantIds.Skip(tenantNumber - 1).First(); + + await Parallel.ForEachAsync(Enumerable.Repeat(true, 10), async (_, _) => + { + var response = await httpClient.PostAsync(new Uri($"http://localhost:6000/invoice/{tenant}"), null); + var invoiceNumber = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Tenant: {tenant}, Invoice #: {invoiceNumber}"); + + }); + } + +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/client/Program.cs b/client/Program.cs new file mode 100644 index 0000000..da35bfc --- /dev/null +++ b/client/Program.cs @@ -0,0 +1,20 @@ +var tenantIds = Enumerable.Range(1, 1000).Select(x => Guid.NewGuid()).ToArray(); +var httpClient = new HttpClient(); + +while (true) +{ + Console.Write("Tenant: "); + if (int.TryParse(Console.ReadLine(), out var tenantNumber)) + { + var tenant = tenantIds.Skip(tenantNumber - 1).First(); + + await Parallel.ForEachAsync(Enumerable.Repeat(true, 10), async (_, _) => + { + var response = await httpClient.PostAsync(new Uri($"http://localhost:6000/invoice/{tenant}"), null); + var invoiceNumber = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Tenant: {tenant}, Invoice #: {invoiceNumber}"); + + }); + } + +} diff --git a/client/client.csproj b/client/client.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/client/client.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/client/Program.cs b/client/Program.cs new file mode 100644 index 0000000..da35bfc --- /dev/null +++ b/client/Program.cs @@ -0,0 +1,20 @@ +var tenantIds = Enumerable.Range(1, 1000).Select(x => Guid.NewGuid()).ToArray(); +var httpClient = new HttpClient(); + +while (true) +{ + Console.Write("Tenant: "); + if (int.TryParse(Console.ReadLine(), out var tenantNumber)) + { + var tenant = tenantIds.Skip(tenantNumber - 1).First(); + + await Parallel.ForEachAsync(Enumerable.Repeat(true, 10), async (_, _) => + { + var response = await httpClient.PostAsync(new Uri($"http://localhost:6000/invoice/{tenant}"), null); + var invoiceNumber = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Tenant: {tenant}, Invoice #: {invoiceNumber}"); + + }); + } + +} diff --git a/client/client.csproj b/client/client.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/client/client.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/domain/InvoiceNumberGeneratorGrain.cs b/domain/InvoiceNumberGeneratorGrain.cs new file mode 100644 index 0000000..eedc294 --- /dev/null +++ b/domain/InvoiceNumberGeneratorGrain.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Logging; +using Orleans; + +public interface IInvoiceNumberGeneratorGrain : IGrainWithGuidKey +{ + public Task ReserveInvoiceNumber(); +} + +public class InvoiceNumberGeneratorGrain : Grain, IInvoiceNumberGeneratorGrain +{ + private readonly ILogger _logger; + private int _currentInvoiceNumber = 0; + + public InvoiceNumberGeneratorGrain(ILogger logger) + { + _logger = logger; + } + + public override Task OnActivateAsync() + { + // Fetch Data from database or use persistence + return base.OnActivateAsync(); + } + + public Task ReserveInvoiceNumber() + { + _logger.LogInformation($"Executing in Grain Tenant: {this.GetPrimaryKey()}, Invoice #: {_currentInvoiceNumber}"); + + _currentInvoiceNumber++; + return Task.FromResult(_currentInvoiceNumber); + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/client/Program.cs b/client/Program.cs new file mode 100644 index 0000000..da35bfc --- /dev/null +++ b/client/Program.cs @@ -0,0 +1,20 @@ +var tenantIds = Enumerable.Range(1, 1000).Select(x => Guid.NewGuid()).ToArray(); +var httpClient = new HttpClient(); + +while (true) +{ + Console.Write("Tenant: "); + if (int.TryParse(Console.ReadLine(), out var tenantNumber)) + { + var tenant = tenantIds.Skip(tenantNumber - 1).First(); + + await Parallel.ForEachAsync(Enumerable.Repeat(true, 10), async (_, _) => + { + var response = await httpClient.PostAsync(new Uri($"http://localhost:6000/invoice/{tenant}"), null); + var invoiceNumber = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Tenant: {tenant}, Invoice #: {invoiceNumber}"); + + }); + } + +} diff --git a/client/client.csproj b/client/client.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/client/client.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/domain/InvoiceNumberGeneratorGrain.cs b/domain/InvoiceNumberGeneratorGrain.cs new file mode 100644 index 0000000..eedc294 --- /dev/null +++ b/domain/InvoiceNumberGeneratorGrain.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Logging; +using Orleans; + +public interface IInvoiceNumberGeneratorGrain : IGrainWithGuidKey +{ + public Task ReserveInvoiceNumber(); +} + +public class InvoiceNumberGeneratorGrain : Grain, IInvoiceNumberGeneratorGrain +{ + private readonly ILogger _logger; + private int _currentInvoiceNumber = 0; + + public InvoiceNumberGeneratorGrain(ILogger logger) + { + _logger = logger; + } + + public override Task OnActivateAsync() + { + // Fetch Data from database or use persistence + return base.OnActivateAsync(); + } + + public Task ReserveInvoiceNumber() + { + _logger.LogInformation($"Executing in Grain Tenant: {this.GetPrimaryKey()}, Invoice #: {_currentInvoiceNumber}"); + + _currentInvoiceNumber++; + return Task.FromResult(_currentInvoiceNumber); + } +} \ No newline at end of file diff --git a/domain/domain.csproj b/domain/domain.csproj new file mode 100644 index 0000000..8ceca80 --- /dev/null +++ b/domain/domain.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/client/Program.cs b/client/Program.cs new file mode 100644 index 0000000..da35bfc --- /dev/null +++ b/client/Program.cs @@ -0,0 +1,20 @@ +var tenantIds = Enumerable.Range(1, 1000).Select(x => Guid.NewGuid()).ToArray(); +var httpClient = new HttpClient(); + +while (true) +{ + Console.Write("Tenant: "); + if (int.TryParse(Console.ReadLine(), out var tenantNumber)) + { + var tenant = tenantIds.Skip(tenantNumber - 1).First(); + + await Parallel.ForEachAsync(Enumerable.Repeat(true, 10), async (_, _) => + { + var response = await httpClient.PostAsync(new Uri($"http://localhost:6000/invoice/{tenant}"), null); + var invoiceNumber = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Tenant: {tenant}, Invoice #: {invoiceNumber}"); + + }); + } + +} diff --git a/client/client.csproj b/client/client.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/client/client.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/domain/InvoiceNumberGeneratorGrain.cs b/domain/InvoiceNumberGeneratorGrain.cs new file mode 100644 index 0000000..eedc294 --- /dev/null +++ b/domain/InvoiceNumberGeneratorGrain.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Logging; +using Orleans; + +public interface IInvoiceNumberGeneratorGrain : IGrainWithGuidKey +{ + public Task ReserveInvoiceNumber(); +} + +public class InvoiceNumberGeneratorGrain : Grain, IInvoiceNumberGeneratorGrain +{ + private readonly ILogger _logger; + private int _currentInvoiceNumber = 0; + + public InvoiceNumberGeneratorGrain(ILogger logger) + { + _logger = logger; + } + + public override Task OnActivateAsync() + { + // Fetch Data from database or use persistence + return base.OnActivateAsync(); + } + + public Task ReserveInvoiceNumber() + { + _logger.LogInformation($"Executing in Grain Tenant: {this.GetPrimaryKey()}, Invoice #: {_currentInvoiceNumber}"); + + _currentInvoiceNumber++; + return Task.FromResult(_currentInvoiceNumber); + } +} \ No newline at end of file diff --git a/domain/domain.csproj b/domain/domain.csproj new file mode 100644 index 0000000..8ceca80 --- /dev/null +++ b/domain/domain.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + diff --git a/httpapi/Program.cs b/httpapi/Program.cs new file mode 100644 index 0000000..39237dd --- /dev/null +++ b/httpapi/Program.cs @@ -0,0 +1,47 @@ +using httpapi; +using Orleans; +using Orleans.Hosting; +using Polly; + +var client = await Policy + .Handle() + .WaitAndRetryAsync(new[] + { + TimeSpan.FromSeconds(1), + TimeSpan.FromSeconds(2), + TimeSpan.FromSeconds(3) + }) + .ExecuteAsync(async () => + { + var client = new ClientBuilder() + .UseLocalhostClustering() + .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IInvoiceNumberGeneratorGrain).Assembly)) + .Build(); + + await client.Connect(); + + return client; + }); + +var builder = Host.CreateDefaultBuilder(args); + +/* +builder.UseOrleans(siloBuilder => +{ + siloBuilder.UseLocalhostClustering(11111, 30000); + siloBuilder.AddMemoryGrainStorage("Demo"); +}); +*/ + +builder.ConfigureWebHostDefaults(hostBuilder => +{ + hostBuilder.UseUrls("http://localhost:6000"); + hostBuilder.UseStartup(); +}); +builder.ConfigureServices(collection => +{ + collection.AddSingleton(client); +}); + +var app = builder.Build(); +app.Run(); diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/client/Program.cs b/client/Program.cs new file mode 100644 index 0000000..da35bfc --- /dev/null +++ b/client/Program.cs @@ -0,0 +1,20 @@ +var tenantIds = Enumerable.Range(1, 1000).Select(x => Guid.NewGuid()).ToArray(); +var httpClient = new HttpClient(); + +while (true) +{ + Console.Write("Tenant: "); + if (int.TryParse(Console.ReadLine(), out var tenantNumber)) + { + var tenant = tenantIds.Skip(tenantNumber - 1).First(); + + await Parallel.ForEachAsync(Enumerable.Repeat(true, 10), async (_, _) => + { + var response = await httpClient.PostAsync(new Uri($"http://localhost:6000/invoice/{tenant}"), null); + var invoiceNumber = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Tenant: {tenant}, Invoice #: {invoiceNumber}"); + + }); + } + +} diff --git a/client/client.csproj b/client/client.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/client/client.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/domain/InvoiceNumberGeneratorGrain.cs b/domain/InvoiceNumberGeneratorGrain.cs new file mode 100644 index 0000000..eedc294 --- /dev/null +++ b/domain/InvoiceNumberGeneratorGrain.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Logging; +using Orleans; + +public interface IInvoiceNumberGeneratorGrain : IGrainWithGuidKey +{ + public Task ReserveInvoiceNumber(); +} + +public class InvoiceNumberGeneratorGrain : Grain, IInvoiceNumberGeneratorGrain +{ + private readonly ILogger _logger; + private int _currentInvoiceNumber = 0; + + public InvoiceNumberGeneratorGrain(ILogger logger) + { + _logger = logger; + } + + public override Task OnActivateAsync() + { + // Fetch Data from database or use persistence + return base.OnActivateAsync(); + } + + public Task ReserveInvoiceNumber() + { + _logger.LogInformation($"Executing in Grain Tenant: {this.GetPrimaryKey()}, Invoice #: {_currentInvoiceNumber}"); + + _currentInvoiceNumber++; + return Task.FromResult(_currentInvoiceNumber); + } +} \ No newline at end of file diff --git a/domain/domain.csproj b/domain/domain.csproj new file mode 100644 index 0000000..8ceca80 --- /dev/null +++ b/domain/domain.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + diff --git a/httpapi/Program.cs b/httpapi/Program.cs new file mode 100644 index 0000000..39237dd --- /dev/null +++ b/httpapi/Program.cs @@ -0,0 +1,47 @@ +using httpapi; +using Orleans; +using Orleans.Hosting; +using Polly; + +var client = await Policy + .Handle() + .WaitAndRetryAsync(new[] + { + TimeSpan.FromSeconds(1), + TimeSpan.FromSeconds(2), + TimeSpan.FromSeconds(3) + }) + .ExecuteAsync(async () => + { + var client = new ClientBuilder() + .UseLocalhostClustering() + .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IInvoiceNumberGeneratorGrain).Assembly)) + .Build(); + + await client.Connect(); + + return client; + }); + +var builder = Host.CreateDefaultBuilder(args); + +/* +builder.UseOrleans(siloBuilder => +{ + siloBuilder.UseLocalhostClustering(11111, 30000); + siloBuilder.AddMemoryGrainStorage("Demo"); +}); +*/ + +builder.ConfigureWebHostDefaults(hostBuilder => +{ + hostBuilder.UseUrls("http://localhost:6000"); + hostBuilder.UseStartup(); +}); +builder.ConfigureServices(collection => +{ + collection.AddSingleton(client); +}); + +var app = builder.Build(); +app.Run(); diff --git a/httpapi/Properties/launchSettings.json b/httpapi/Properties/launchSettings.json new file mode 100644 index 0000000..e0ad532 --- /dev/null +++ b/httpapi/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:56309", + "sslPort": 44317 + } + }, + "profiles": { + "httpapi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7005;http://localhost:5017", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/client/Program.cs b/client/Program.cs new file mode 100644 index 0000000..da35bfc --- /dev/null +++ b/client/Program.cs @@ -0,0 +1,20 @@ +var tenantIds = Enumerable.Range(1, 1000).Select(x => Guid.NewGuid()).ToArray(); +var httpClient = new HttpClient(); + +while (true) +{ + Console.Write("Tenant: "); + if (int.TryParse(Console.ReadLine(), out var tenantNumber)) + { + var tenant = tenantIds.Skip(tenantNumber - 1).First(); + + await Parallel.ForEachAsync(Enumerable.Repeat(true, 10), async (_, _) => + { + var response = await httpClient.PostAsync(new Uri($"http://localhost:6000/invoice/{tenant}"), null); + var invoiceNumber = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Tenant: {tenant}, Invoice #: {invoiceNumber}"); + + }); + } + +} diff --git a/client/client.csproj b/client/client.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/client/client.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/domain/InvoiceNumberGeneratorGrain.cs b/domain/InvoiceNumberGeneratorGrain.cs new file mode 100644 index 0000000..eedc294 --- /dev/null +++ b/domain/InvoiceNumberGeneratorGrain.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Logging; +using Orleans; + +public interface IInvoiceNumberGeneratorGrain : IGrainWithGuidKey +{ + public Task ReserveInvoiceNumber(); +} + +public class InvoiceNumberGeneratorGrain : Grain, IInvoiceNumberGeneratorGrain +{ + private readonly ILogger _logger; + private int _currentInvoiceNumber = 0; + + public InvoiceNumberGeneratorGrain(ILogger logger) + { + _logger = logger; + } + + public override Task OnActivateAsync() + { + // Fetch Data from database or use persistence + return base.OnActivateAsync(); + } + + public Task ReserveInvoiceNumber() + { + _logger.LogInformation($"Executing in Grain Tenant: {this.GetPrimaryKey()}, Invoice #: {_currentInvoiceNumber}"); + + _currentInvoiceNumber++; + return Task.FromResult(_currentInvoiceNumber); + } +} \ No newline at end of file diff --git a/domain/domain.csproj b/domain/domain.csproj new file mode 100644 index 0000000..8ceca80 --- /dev/null +++ b/domain/domain.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + diff --git a/httpapi/Program.cs b/httpapi/Program.cs new file mode 100644 index 0000000..39237dd --- /dev/null +++ b/httpapi/Program.cs @@ -0,0 +1,47 @@ +using httpapi; +using Orleans; +using Orleans.Hosting; +using Polly; + +var client = await Policy + .Handle() + .WaitAndRetryAsync(new[] + { + TimeSpan.FromSeconds(1), + TimeSpan.FromSeconds(2), + TimeSpan.FromSeconds(3) + }) + .ExecuteAsync(async () => + { + var client = new ClientBuilder() + .UseLocalhostClustering() + .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IInvoiceNumberGeneratorGrain).Assembly)) + .Build(); + + await client.Connect(); + + return client; + }); + +var builder = Host.CreateDefaultBuilder(args); + +/* +builder.UseOrleans(siloBuilder => +{ + siloBuilder.UseLocalhostClustering(11111, 30000); + siloBuilder.AddMemoryGrainStorage("Demo"); +}); +*/ + +builder.ConfigureWebHostDefaults(hostBuilder => +{ + hostBuilder.UseUrls("http://localhost:6000"); + hostBuilder.UseStartup(); +}); +builder.ConfigureServices(collection => +{ + collection.AddSingleton(client); +}); + +var app = builder.Build(); +app.Run(); diff --git a/httpapi/Properties/launchSettings.json b/httpapi/Properties/launchSettings.json new file mode 100644 index 0000000..e0ad532 --- /dev/null +++ b/httpapi/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:56309", + "sslPort": 44317 + } + }, + "profiles": { + "httpapi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7005;http://localhost:5017", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/httpapi/Startup.cs b/httpapi/Startup.cs new file mode 100644 index 0000000..ae1bf3e --- /dev/null +++ b/httpapi/Startup.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Mvc; +using Orleans; + +namespace httpapi; + +public class Startup +{ + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseDeveloperExceptionPage(); + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapPost("/invoice/{tenantId}", + async ([FromServices]IClusterClient clusterClient, [FromRoute]Guid tenantId) => + { + var invoiceNumberGeneratorGrain = clusterClient + .GetGrain(tenantId); + + return await invoiceNumberGeneratorGrain.ReserveInvoiceNumber(); + }); + }); + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/client/Program.cs b/client/Program.cs new file mode 100644 index 0000000..da35bfc --- /dev/null +++ b/client/Program.cs @@ -0,0 +1,20 @@ +var tenantIds = Enumerable.Range(1, 1000).Select(x => Guid.NewGuid()).ToArray(); +var httpClient = new HttpClient(); + +while (true) +{ + Console.Write("Tenant: "); + if (int.TryParse(Console.ReadLine(), out var tenantNumber)) + { + var tenant = tenantIds.Skip(tenantNumber - 1).First(); + + await Parallel.ForEachAsync(Enumerable.Repeat(true, 10), async (_, _) => + { + var response = await httpClient.PostAsync(new Uri($"http://localhost:6000/invoice/{tenant}"), null); + var invoiceNumber = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Tenant: {tenant}, Invoice #: {invoiceNumber}"); + + }); + } + +} diff --git a/client/client.csproj b/client/client.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/client/client.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/domain/InvoiceNumberGeneratorGrain.cs b/domain/InvoiceNumberGeneratorGrain.cs new file mode 100644 index 0000000..eedc294 --- /dev/null +++ b/domain/InvoiceNumberGeneratorGrain.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Logging; +using Orleans; + +public interface IInvoiceNumberGeneratorGrain : IGrainWithGuidKey +{ + public Task ReserveInvoiceNumber(); +} + +public class InvoiceNumberGeneratorGrain : Grain, IInvoiceNumberGeneratorGrain +{ + private readonly ILogger _logger; + private int _currentInvoiceNumber = 0; + + public InvoiceNumberGeneratorGrain(ILogger logger) + { + _logger = logger; + } + + public override Task OnActivateAsync() + { + // Fetch Data from database or use persistence + return base.OnActivateAsync(); + } + + public Task ReserveInvoiceNumber() + { + _logger.LogInformation($"Executing in Grain Tenant: {this.GetPrimaryKey()}, Invoice #: {_currentInvoiceNumber}"); + + _currentInvoiceNumber++; + return Task.FromResult(_currentInvoiceNumber); + } +} \ No newline at end of file diff --git a/domain/domain.csproj b/domain/domain.csproj new file mode 100644 index 0000000..8ceca80 --- /dev/null +++ b/domain/domain.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + diff --git a/httpapi/Program.cs b/httpapi/Program.cs new file mode 100644 index 0000000..39237dd --- /dev/null +++ b/httpapi/Program.cs @@ -0,0 +1,47 @@ +using httpapi; +using Orleans; +using Orleans.Hosting; +using Polly; + +var client = await Policy + .Handle() + .WaitAndRetryAsync(new[] + { + TimeSpan.FromSeconds(1), + TimeSpan.FromSeconds(2), + TimeSpan.FromSeconds(3) + }) + .ExecuteAsync(async () => + { + var client = new ClientBuilder() + .UseLocalhostClustering() + .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IInvoiceNumberGeneratorGrain).Assembly)) + .Build(); + + await client.Connect(); + + return client; + }); + +var builder = Host.CreateDefaultBuilder(args); + +/* +builder.UseOrleans(siloBuilder => +{ + siloBuilder.UseLocalhostClustering(11111, 30000); + siloBuilder.AddMemoryGrainStorage("Demo"); +}); +*/ + +builder.ConfigureWebHostDefaults(hostBuilder => +{ + hostBuilder.UseUrls("http://localhost:6000"); + hostBuilder.UseStartup(); +}); +builder.ConfigureServices(collection => +{ + collection.AddSingleton(client); +}); + +var app = builder.Build(); +app.Run(); diff --git a/httpapi/Properties/launchSettings.json b/httpapi/Properties/launchSettings.json new file mode 100644 index 0000000..e0ad532 --- /dev/null +++ b/httpapi/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:56309", + "sslPort": 44317 + } + }, + "profiles": { + "httpapi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7005;http://localhost:5017", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/httpapi/Startup.cs b/httpapi/Startup.cs new file mode 100644 index 0000000..ae1bf3e --- /dev/null +++ b/httpapi/Startup.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Mvc; +using Orleans; + +namespace httpapi; + +public class Startup +{ + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseDeveloperExceptionPage(); + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapPost("/invoice/{tenantId}", + async ([FromServices]IClusterClient clusterClient, [FromRoute]Guid tenantId) => + { + var invoiceNumberGeneratorGrain = clusterClient + .GetGrain(tenantId); + + return await invoiceNumberGeneratorGrain.ReserveInvoiceNumber(); + }); + }); + } +} \ No newline at end of file diff --git a/httpapi/appsettings.Development.json b/httpapi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/httpapi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/client/Program.cs b/client/Program.cs new file mode 100644 index 0000000..da35bfc --- /dev/null +++ b/client/Program.cs @@ -0,0 +1,20 @@ +var tenantIds = Enumerable.Range(1, 1000).Select(x => Guid.NewGuid()).ToArray(); +var httpClient = new HttpClient(); + +while (true) +{ + Console.Write("Tenant: "); + if (int.TryParse(Console.ReadLine(), out var tenantNumber)) + { + var tenant = tenantIds.Skip(tenantNumber - 1).First(); + + await Parallel.ForEachAsync(Enumerable.Repeat(true, 10), async (_, _) => + { + var response = await httpClient.PostAsync(new Uri($"http://localhost:6000/invoice/{tenant}"), null); + var invoiceNumber = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Tenant: {tenant}, Invoice #: {invoiceNumber}"); + + }); + } + +} diff --git a/client/client.csproj b/client/client.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/client/client.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/domain/InvoiceNumberGeneratorGrain.cs b/domain/InvoiceNumberGeneratorGrain.cs new file mode 100644 index 0000000..eedc294 --- /dev/null +++ b/domain/InvoiceNumberGeneratorGrain.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Logging; +using Orleans; + +public interface IInvoiceNumberGeneratorGrain : IGrainWithGuidKey +{ + public Task ReserveInvoiceNumber(); +} + +public class InvoiceNumberGeneratorGrain : Grain, IInvoiceNumberGeneratorGrain +{ + private readonly ILogger _logger; + private int _currentInvoiceNumber = 0; + + public InvoiceNumberGeneratorGrain(ILogger logger) + { + _logger = logger; + } + + public override Task OnActivateAsync() + { + // Fetch Data from database or use persistence + return base.OnActivateAsync(); + } + + public Task ReserveInvoiceNumber() + { + _logger.LogInformation($"Executing in Grain Tenant: {this.GetPrimaryKey()}, Invoice #: {_currentInvoiceNumber}"); + + _currentInvoiceNumber++; + return Task.FromResult(_currentInvoiceNumber); + } +} \ No newline at end of file diff --git a/domain/domain.csproj b/domain/domain.csproj new file mode 100644 index 0000000..8ceca80 --- /dev/null +++ b/domain/domain.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + diff --git a/httpapi/Program.cs b/httpapi/Program.cs new file mode 100644 index 0000000..39237dd --- /dev/null +++ b/httpapi/Program.cs @@ -0,0 +1,47 @@ +using httpapi; +using Orleans; +using Orleans.Hosting; +using Polly; + +var client = await Policy + .Handle() + .WaitAndRetryAsync(new[] + { + TimeSpan.FromSeconds(1), + TimeSpan.FromSeconds(2), + TimeSpan.FromSeconds(3) + }) + .ExecuteAsync(async () => + { + var client = new ClientBuilder() + .UseLocalhostClustering() + .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IInvoiceNumberGeneratorGrain).Assembly)) + .Build(); + + await client.Connect(); + + return client; + }); + +var builder = Host.CreateDefaultBuilder(args); + +/* +builder.UseOrleans(siloBuilder => +{ + siloBuilder.UseLocalhostClustering(11111, 30000); + siloBuilder.AddMemoryGrainStorage("Demo"); +}); +*/ + +builder.ConfigureWebHostDefaults(hostBuilder => +{ + hostBuilder.UseUrls("http://localhost:6000"); + hostBuilder.UseStartup(); +}); +builder.ConfigureServices(collection => +{ + collection.AddSingleton(client); +}); + +var app = builder.Build(); +app.Run(); diff --git a/httpapi/Properties/launchSettings.json b/httpapi/Properties/launchSettings.json new file mode 100644 index 0000000..e0ad532 --- /dev/null +++ b/httpapi/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:56309", + "sslPort": 44317 + } + }, + "profiles": { + "httpapi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7005;http://localhost:5017", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/httpapi/Startup.cs b/httpapi/Startup.cs new file mode 100644 index 0000000..ae1bf3e --- /dev/null +++ b/httpapi/Startup.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Mvc; +using Orleans; + +namespace httpapi; + +public class Startup +{ + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseDeveloperExceptionPage(); + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapPost("/invoice/{tenantId}", + async ([FromServices]IClusterClient clusterClient, [FromRoute]Guid tenantId) => + { + var invoiceNumberGeneratorGrain = clusterClient + .GetGrain(tenantId); + + return await invoiceNumberGeneratorGrain.ReserveInvoiceNumber(); + }); + }); + } +} \ No newline at end of file diff --git a/httpapi/appsettings.Development.json b/httpapi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/httpapi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/httpapi/appsettings.json b/httpapi/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/httpapi/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/client/Program.cs b/client/Program.cs new file mode 100644 index 0000000..da35bfc --- /dev/null +++ b/client/Program.cs @@ -0,0 +1,20 @@ +var tenantIds = Enumerable.Range(1, 1000).Select(x => Guid.NewGuid()).ToArray(); +var httpClient = new HttpClient(); + +while (true) +{ + Console.Write("Tenant: "); + if (int.TryParse(Console.ReadLine(), out var tenantNumber)) + { + var tenant = tenantIds.Skip(tenantNumber - 1).First(); + + await Parallel.ForEachAsync(Enumerable.Repeat(true, 10), async (_, _) => + { + var response = await httpClient.PostAsync(new Uri($"http://localhost:6000/invoice/{tenant}"), null); + var invoiceNumber = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Tenant: {tenant}, Invoice #: {invoiceNumber}"); + + }); + } + +} diff --git a/client/client.csproj b/client/client.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/client/client.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/domain/InvoiceNumberGeneratorGrain.cs b/domain/InvoiceNumberGeneratorGrain.cs new file mode 100644 index 0000000..eedc294 --- /dev/null +++ b/domain/InvoiceNumberGeneratorGrain.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Logging; +using Orleans; + +public interface IInvoiceNumberGeneratorGrain : IGrainWithGuidKey +{ + public Task ReserveInvoiceNumber(); +} + +public class InvoiceNumberGeneratorGrain : Grain, IInvoiceNumberGeneratorGrain +{ + private readonly ILogger _logger; + private int _currentInvoiceNumber = 0; + + public InvoiceNumberGeneratorGrain(ILogger logger) + { + _logger = logger; + } + + public override Task OnActivateAsync() + { + // Fetch Data from database or use persistence + return base.OnActivateAsync(); + } + + public Task ReserveInvoiceNumber() + { + _logger.LogInformation($"Executing in Grain Tenant: {this.GetPrimaryKey()}, Invoice #: {_currentInvoiceNumber}"); + + _currentInvoiceNumber++; + return Task.FromResult(_currentInvoiceNumber); + } +} \ No newline at end of file diff --git a/domain/domain.csproj b/domain/domain.csproj new file mode 100644 index 0000000..8ceca80 --- /dev/null +++ b/domain/domain.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + diff --git a/httpapi/Program.cs b/httpapi/Program.cs new file mode 100644 index 0000000..39237dd --- /dev/null +++ b/httpapi/Program.cs @@ -0,0 +1,47 @@ +using httpapi; +using Orleans; +using Orleans.Hosting; +using Polly; + +var client = await Policy + .Handle() + .WaitAndRetryAsync(new[] + { + TimeSpan.FromSeconds(1), + TimeSpan.FromSeconds(2), + TimeSpan.FromSeconds(3) + }) + .ExecuteAsync(async () => + { + var client = new ClientBuilder() + .UseLocalhostClustering() + .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IInvoiceNumberGeneratorGrain).Assembly)) + .Build(); + + await client.Connect(); + + return client; + }); + +var builder = Host.CreateDefaultBuilder(args); + +/* +builder.UseOrleans(siloBuilder => +{ + siloBuilder.UseLocalhostClustering(11111, 30000); + siloBuilder.AddMemoryGrainStorage("Demo"); +}); +*/ + +builder.ConfigureWebHostDefaults(hostBuilder => +{ + hostBuilder.UseUrls("http://localhost:6000"); + hostBuilder.UseStartup(); +}); +builder.ConfigureServices(collection => +{ + collection.AddSingleton(client); +}); + +var app = builder.Build(); +app.Run(); diff --git a/httpapi/Properties/launchSettings.json b/httpapi/Properties/launchSettings.json new file mode 100644 index 0000000..e0ad532 --- /dev/null +++ b/httpapi/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:56309", + "sslPort": 44317 + } + }, + "profiles": { + "httpapi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7005;http://localhost:5017", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/httpapi/Startup.cs b/httpapi/Startup.cs new file mode 100644 index 0000000..ae1bf3e --- /dev/null +++ b/httpapi/Startup.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Mvc; +using Orleans; + +namespace httpapi; + +public class Startup +{ + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseDeveloperExceptionPage(); + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapPost("/invoice/{tenantId}", + async ([FromServices]IClusterClient clusterClient, [FromRoute]Guid tenantId) => + { + var invoiceNumberGeneratorGrain = clusterClient + .GetGrain(tenantId); + + return await invoiceNumberGeneratorGrain.ReserveInvoiceNumber(); + }); + }); + } +} \ No newline at end of file diff --git a/httpapi/appsettings.Development.json b/httpapi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/httpapi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/httpapi/appsettings.json b/httpapi/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/httpapi/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/httpapi/httpapi.csproj b/httpapi/httpapi.csproj new file mode 100644 index 0000000..a19cd6a --- /dev/null +++ b/httpapi/httpapi.csproj @@ -0,0 +1,25 @@ + + + + net6.0 + enable + enable + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/client/Program.cs b/client/Program.cs new file mode 100644 index 0000000..da35bfc --- /dev/null +++ b/client/Program.cs @@ -0,0 +1,20 @@ +var tenantIds = Enumerable.Range(1, 1000).Select(x => Guid.NewGuid()).ToArray(); +var httpClient = new HttpClient(); + +while (true) +{ + Console.Write("Tenant: "); + if (int.TryParse(Console.ReadLine(), out var tenantNumber)) + { + var tenant = tenantIds.Skip(tenantNumber - 1).First(); + + await Parallel.ForEachAsync(Enumerable.Repeat(true, 10), async (_, _) => + { + var response = await httpClient.PostAsync(new Uri($"http://localhost:6000/invoice/{tenant}"), null); + var invoiceNumber = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Tenant: {tenant}, Invoice #: {invoiceNumber}"); + + }); + } + +} diff --git a/client/client.csproj b/client/client.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/client/client.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/domain/InvoiceNumberGeneratorGrain.cs b/domain/InvoiceNumberGeneratorGrain.cs new file mode 100644 index 0000000..eedc294 --- /dev/null +++ b/domain/InvoiceNumberGeneratorGrain.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Logging; +using Orleans; + +public interface IInvoiceNumberGeneratorGrain : IGrainWithGuidKey +{ + public Task ReserveInvoiceNumber(); +} + +public class InvoiceNumberGeneratorGrain : Grain, IInvoiceNumberGeneratorGrain +{ + private readonly ILogger _logger; + private int _currentInvoiceNumber = 0; + + public InvoiceNumberGeneratorGrain(ILogger logger) + { + _logger = logger; + } + + public override Task OnActivateAsync() + { + // Fetch Data from database or use persistence + return base.OnActivateAsync(); + } + + public Task ReserveInvoiceNumber() + { + _logger.LogInformation($"Executing in Grain Tenant: {this.GetPrimaryKey()}, Invoice #: {_currentInvoiceNumber}"); + + _currentInvoiceNumber++; + return Task.FromResult(_currentInvoiceNumber); + } +} \ No newline at end of file diff --git a/domain/domain.csproj b/domain/domain.csproj new file mode 100644 index 0000000..8ceca80 --- /dev/null +++ b/domain/domain.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + diff --git a/httpapi/Program.cs b/httpapi/Program.cs new file mode 100644 index 0000000..39237dd --- /dev/null +++ b/httpapi/Program.cs @@ -0,0 +1,47 @@ +using httpapi; +using Orleans; +using Orleans.Hosting; +using Polly; + +var client = await Policy + .Handle() + .WaitAndRetryAsync(new[] + { + TimeSpan.FromSeconds(1), + TimeSpan.FromSeconds(2), + TimeSpan.FromSeconds(3) + }) + .ExecuteAsync(async () => + { + var client = new ClientBuilder() + .UseLocalhostClustering() + .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IInvoiceNumberGeneratorGrain).Assembly)) + .Build(); + + await client.Connect(); + + return client; + }); + +var builder = Host.CreateDefaultBuilder(args); + +/* +builder.UseOrleans(siloBuilder => +{ + siloBuilder.UseLocalhostClustering(11111, 30000); + siloBuilder.AddMemoryGrainStorage("Demo"); +}); +*/ + +builder.ConfigureWebHostDefaults(hostBuilder => +{ + hostBuilder.UseUrls("http://localhost:6000"); + hostBuilder.UseStartup(); +}); +builder.ConfigureServices(collection => +{ + collection.AddSingleton(client); +}); + +var app = builder.Build(); +app.Run(); diff --git a/httpapi/Properties/launchSettings.json b/httpapi/Properties/launchSettings.json new file mode 100644 index 0000000..e0ad532 --- /dev/null +++ b/httpapi/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:56309", + "sslPort": 44317 + } + }, + "profiles": { + "httpapi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7005;http://localhost:5017", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/httpapi/Startup.cs b/httpapi/Startup.cs new file mode 100644 index 0000000..ae1bf3e --- /dev/null +++ b/httpapi/Startup.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Mvc; +using Orleans; + +namespace httpapi; + +public class Startup +{ + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseDeveloperExceptionPage(); + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapPost("/invoice/{tenantId}", + async ([FromServices]IClusterClient clusterClient, [FromRoute]Guid tenantId) => + { + var invoiceNumberGeneratorGrain = clusterClient + .GetGrain(tenantId); + + return await invoiceNumberGeneratorGrain.ReserveInvoiceNumber(); + }); + }); + } +} \ No newline at end of file diff --git a/httpapi/appsettings.Development.json b/httpapi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/httpapi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/httpapi/appsettings.json b/httpapi/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/httpapi/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/httpapi/httpapi.csproj b/httpapi/httpapi.csproj new file mode 100644 index 0000000..a19cd6a --- /dev/null +++ b/httpapi/httpapi.csproj @@ -0,0 +1,25 @@ + + + + net6.0 + enable + enable + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + diff --git a/silo/Program.cs b/silo/Program.cs new file mode 100644 index 0000000..8a3c420 --- /dev/null +++ b/silo/Program.cs @@ -0,0 +1,13 @@ +using System.Net; +using Orleans.Hosting; + +var builder = Host.CreateDefaultBuilder(args); +builder.UseOrleans(siloBuilder => +{ + var port = args.Any() ? Convert.ToInt32(args[0]) : 11111; + siloBuilder.UseLocalhostClustering(port, 30000, new IPEndPoint(IPAddress.Loopback, 11111)); + siloBuilder.AddMemoryGrainStorage("Demo"); +}); + +var app = builder.Build(); +app.Run(); \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea5ebf9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,205 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +x64/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# AWS +*.aws-sam/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +# NuGet Packages Directory +#packages/* +## TODO: If the tool you use requires repositories.config +## uncomment the next line +#!packages/repositories.config + +# Enable "build/" folder in the NuGet Packages folder since +# NuGet packages use it for MSBuild targets. +# This line needs to be after the ignore of the build folder +# (and the packages folder if the line above has been uncommented) +#!packages/build/ + +!src/packages/**/*.dll +!src/packages/**/*.pdb + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml +src/packages/EventStore.Client.3.3.1/lib/net40/EventStore.ClientAPI.xml + +# JetBrains Rider +.idea/ +*.sln.iml + +# Vagrant VM files +.vagrant +vagrant/dbv/data/meta/revision + +# Visual Studio 2015 cache/options directory +.vs/ \ No newline at end of file diff --git a/VirtualActorAggregate.sln b/VirtualActorAggregate.sln new file mode 100644 index 0000000..aca1eb7 --- /dev/null +++ b/VirtualActorAggregate.sln @@ -0,0 +1,40 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "client", "client\client.csproj", "{39ACD6B9-5860-44DD-91FE-3A6970B3DF12}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpapi", "httpapi\httpapi.csproj", "{6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "silo", "silo\silo.csproj", "{DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "domain", "domain\domain.csproj", "{627CB599-50BF-4ECD-AC1B-38BACC3E0B33}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39ACD6B9-5860-44DD-91FE-3A6970B3DF12}.Release|Any CPU.Build.0 = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C0B2B2C-9E30-48C9-8D0B-5D93EF73E299}.Release|Any CPU.Build.0 = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB6940CB-7EC5-4DC7-88AD-A7C60A2441F2}.Release|Any CPU.Build.0 = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627CB599-50BF-4ECD-AC1B-38BACC3E0B33}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/VirtualActorAggregate.sln.DotSettings b/VirtualActorAggregate.sln.DotSettings new file mode 100644 index 0000000..a8acbeb --- /dev/null +++ b/VirtualActorAggregate.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/client/Program.cs b/client/Program.cs new file mode 100644 index 0000000..da35bfc --- /dev/null +++ b/client/Program.cs @@ -0,0 +1,20 @@ +var tenantIds = Enumerable.Range(1, 1000).Select(x => Guid.NewGuid()).ToArray(); +var httpClient = new HttpClient(); + +while (true) +{ + Console.Write("Tenant: "); + if (int.TryParse(Console.ReadLine(), out var tenantNumber)) + { + var tenant = tenantIds.Skip(tenantNumber - 1).First(); + + await Parallel.ForEachAsync(Enumerable.Repeat(true, 10), async (_, _) => + { + var response = await httpClient.PostAsync(new Uri($"http://localhost:6000/invoice/{tenant}"), null); + var invoiceNumber = await response.Content.ReadAsStringAsync(); + Console.WriteLine($"Tenant: {tenant}, Invoice #: {invoiceNumber}"); + + }); + } + +} diff --git a/client/client.csproj b/client/client.csproj new file mode 100644 index 0000000..74abf5c --- /dev/null +++ b/client/client.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/domain/InvoiceNumberGeneratorGrain.cs b/domain/InvoiceNumberGeneratorGrain.cs new file mode 100644 index 0000000..eedc294 --- /dev/null +++ b/domain/InvoiceNumberGeneratorGrain.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Logging; +using Orleans; + +public interface IInvoiceNumberGeneratorGrain : IGrainWithGuidKey +{ + public Task ReserveInvoiceNumber(); +} + +public class InvoiceNumberGeneratorGrain : Grain, IInvoiceNumberGeneratorGrain +{ + private readonly ILogger _logger; + private int _currentInvoiceNumber = 0; + + public InvoiceNumberGeneratorGrain(ILogger logger) + { + _logger = logger; + } + + public override Task OnActivateAsync() + { + // Fetch Data from database or use persistence + return base.OnActivateAsync(); + } + + public Task ReserveInvoiceNumber() + { + _logger.LogInformation($"Executing in Grain Tenant: {this.GetPrimaryKey()}, Invoice #: {_currentInvoiceNumber}"); + + _currentInvoiceNumber++; + return Task.FromResult(_currentInvoiceNumber); + } +} \ No newline at end of file diff --git a/domain/domain.csproj b/domain/domain.csproj new file mode 100644 index 0000000..8ceca80 --- /dev/null +++ b/domain/domain.csproj @@ -0,0 +1,19 @@ + + + + net6.0 + enable + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + diff --git a/httpapi/Program.cs b/httpapi/Program.cs new file mode 100644 index 0000000..39237dd --- /dev/null +++ b/httpapi/Program.cs @@ -0,0 +1,47 @@ +using httpapi; +using Orleans; +using Orleans.Hosting; +using Polly; + +var client = await Policy + .Handle() + .WaitAndRetryAsync(new[] + { + TimeSpan.FromSeconds(1), + TimeSpan.FromSeconds(2), + TimeSpan.FromSeconds(3) + }) + .ExecuteAsync(async () => + { + var client = new ClientBuilder() + .UseLocalhostClustering() + .ConfigureApplicationParts(parts => parts.AddApplicationPart(typeof(IInvoiceNumberGeneratorGrain).Assembly)) + .Build(); + + await client.Connect(); + + return client; + }); + +var builder = Host.CreateDefaultBuilder(args); + +/* +builder.UseOrleans(siloBuilder => +{ + siloBuilder.UseLocalhostClustering(11111, 30000); + siloBuilder.AddMemoryGrainStorage("Demo"); +}); +*/ + +builder.ConfigureWebHostDefaults(hostBuilder => +{ + hostBuilder.UseUrls("http://localhost:6000"); + hostBuilder.UseStartup(); +}); +builder.ConfigureServices(collection => +{ + collection.AddSingleton(client); +}); + +var app = builder.Build(); +app.Run(); diff --git a/httpapi/Properties/launchSettings.json b/httpapi/Properties/launchSettings.json new file mode 100644 index 0000000..e0ad532 --- /dev/null +++ b/httpapi/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:56309", + "sslPort": 44317 + } + }, + "profiles": { + "httpapi": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7005;http://localhost:5017", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/httpapi/Startup.cs b/httpapi/Startup.cs new file mode 100644 index 0000000..ae1bf3e --- /dev/null +++ b/httpapi/Startup.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Mvc; +using Orleans; + +namespace httpapi; + +public class Startup +{ + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.UseDeveloperExceptionPage(); + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapPost("/invoice/{tenantId}", + async ([FromServices]IClusterClient clusterClient, [FromRoute]Guid tenantId) => + { + var invoiceNumberGeneratorGrain = clusterClient + .GetGrain(tenantId); + + return await invoiceNumberGeneratorGrain.ReserveInvoiceNumber(); + }); + }); + } +} \ No newline at end of file diff --git a/httpapi/appsettings.Development.json b/httpapi/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/httpapi/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/httpapi/appsettings.json b/httpapi/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/httpapi/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/httpapi/httpapi.csproj b/httpapi/httpapi.csproj new file mode 100644 index 0000000..a19cd6a --- /dev/null +++ b/httpapi/httpapi.csproj @@ -0,0 +1,25 @@ + + + + net6.0 + enable + enable + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + diff --git a/silo/Program.cs b/silo/Program.cs new file mode 100644 index 0000000..8a3c420 --- /dev/null +++ b/silo/Program.cs @@ -0,0 +1,13 @@ +using System.Net; +using Orleans.Hosting; + +var builder = Host.CreateDefaultBuilder(args); +builder.UseOrleans(siloBuilder => +{ + var port = args.Any() ? Convert.ToInt32(args[0]) : 11111; + siloBuilder.UseLocalhostClustering(port, 30000, new IPEndPoint(IPAddress.Loopback, 11111)); + siloBuilder.AddMemoryGrainStorage("Demo"); +}); + +var app = builder.Build(); +app.Run(); \ No newline at end of file diff --git a/silo/silo.csproj b/silo/silo.csproj new file mode 100644 index 0000000..2a5a5f3 --- /dev/null +++ b/silo/silo.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + enable + enable + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + +