diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 64fe33bbaea..00000000000 --- a/.editorconfig +++ /dev/null @@ -1,11 +0,0 @@ -; This file is for unifying the coding style for different editors and IDEs. -; More information at http://EditorConfig.org - -root = true - -[*] -end_of_line = CRLF - -[*.cs] -indent_style = space -indent_size = 4 diff --git a/.gitattributes b/.gitattributes index b55fe50e1c7..81956b10cdb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -26,4 +26,6 @@ *.sh -text eol=lf # Needed for API Approvals -*.txt text eol=crlf \ No newline at end of file +*.txt text eol=crlf + +build.sh eol=lf diff --git a/.gitignore b/.gitignore index f764f5e3cd1..fc577ea2229 100644 --- a/.gitignore +++ b/.gitignore @@ -1,28 +1,13 @@ -# Akka - -# Fake directories -src/.build/** - - - -#GitExtensions -us.stackdump - -#KDiff3 and other git merge tools -*.orig - -#------------------------------------------------------------------------------- -#Based on https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user +*.userosscache *.sln.docstates -#MonoDevelop +# User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results @@ -36,18 +21,19 @@ build/ bld/ [Bb]in/ [Oo]bj/ +.fake/ +TestResults/ +PerfResults/ +*.lock.json -# Roslyn cache directories -*.ide/ +# Visual Studo 2015 cache/options directory +.vs/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* -# NBench results -[Pp]erf[Rr]esult*/ - -#NUNIT +# NUNIT *.VisualState.xml TestResult.xml @@ -120,9 +106,6 @@ _TeamCity* # NCrunch _NCrunch_* .*crunch*.local.xml -*.ncrunchsolution -*.v2.ncrunchproject - # MightyMoose *.mm.* @@ -150,8 +133,10 @@ publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml -# TODO: Comment out the next line if you want to keep your passwords hidden +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted *.pubxml +*.publishproj # NuGet Packages *.nupkg @@ -159,8 +144,8 @@ publish/ **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ -# If using the old MSBuild-Integrated Package Restore, uncomment this: -!**/packages/repositories.config +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config # Windows Azure Build Output csx/ @@ -170,8 +155,7 @@ csx/ AppPackages/ # Others -sql/ -*.Cache +*.[Cc]ache ClientBin/ [Ss]tyle[Cc]op.* ~$* @@ -181,6 +165,7 @@ ClientBin/ *.pfx *.publishsettings node_modules/ +bower_components/ # RIA/Silverlight projects Generated_Code/ @@ -197,10 +182,6 @@ UpgradeLog*.htm *.mdf *.ldf -# make exception for Akka.Persistence.SqlServer database file -!AkkaPersistenceSqlServerSpecDb.mdf -!AkkaPersistenceSqlServerSpecDb_log.ldf - # Business Intelligence projects *.rdl.data *.bim.layout @@ -208,24 +189,20 @@ UpgradeLog*.htm # Microsoft Fakes FakesAssemblies/ -/src/.Akka.boltdata/NCover/Executions/0.jf -/src/.Akka.boltdata/NCover/Executions/ProjectId/0.jf -/src/.Akka.boltdata/NCover/Executions/ProjectOrderIndex/0.jf -/src/.Akka.boltdata/NCover/Projects/0.jf -/src/.Akka.boltdata/NCover/Projects/Name/0.jf -/src/.Akka.boltdata/Settings.json -/src/.Akka.boltdata/TestResults.json -resetdev.bat -/src/packages/repositories.config - -# FAKE build folder -.fake/ -# Akka.Persistence Test Output -target/ +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg -# API Approval received files -**/Akka.API.Tests/*.received.txt +# Visual Studio 6 workspace options file +*.opt -# include self-signed test certificate for SSL Tests -!src/core/Akka.Remote.Tests/Resources/akka-validcert.pfx \ No newline at end of file +tools/ +build/ +.nuget/ +.dotnet/ +/src/core/Akka.API.Tests/CoreAPISpec.ApproveStreams.received.txt +launchSettings.json +.idea/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c8afe3308f5..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: objective-c - -env: - matrix: - - MONO_VERSION="3.6.0" - -before_install: - - wget "http://download.mono-project.com/archive/${MONO_VERSION}/macos-10-x86/MonoFramework-MDK-${MONO_VERSION}.macos10.xamarin.x86.pkg" - - sudo installer -pkg "MonoFramework-MDK-${MONO_VERSION}.macos10.xamarin.x86.pkg" -target / - -script: - - ./build.sh BuildMono - - ./build.sh RunTestsMono diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 789dcb4c886..d9a9cbacd2f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,7 +17,7 @@ If you have commits that looks like this _"Merge branch 'my-branch' into dev"_ o After reviewing a Pull request, we might ask you to fix some commits. After you've done that you need to force push to update your branch in your local fork. -####Title and Description for the Pull Request#### +#### Title and Description for the Pull Request Give the PR a descriptive title and in the description field describe what you have done in general terms and why. This will help the reviewers greatly, and provide a history for the future. Especially if you modify something existing, be very clear! Have you changed any algorithms, or did you just intend to reorder the code? Justify why the changes are needed. diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 00000000000..2dce55c6e53 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,6 @@ +When creating a new issue, please make sure the following information is part of your issue description. (if applicable). Thank You! + +- Which Akka.Net version you are using +- On which platform you are using Akka.Net +- A list of steps to reproduce the issue. Or an gist or github repo which can be easily used to reproduce your case. + diff --git a/README.md b/README.md index 254009a9784..dcde48d3a56 100644 --- a/README.md +++ b/README.md @@ -47,9 +47,9 @@ PM> Install-Package Akka.FSharp ### Contributing #### Where Can I Contribute? -[![Critical Issues](https://badge.waffle.io/akkadotnet/akka.net.svg?label=help%20wanted&title=Issues Needing Help Now!)](http://waffle.io/akkadotnet/akka.net) +[![Critical Issues](https://badge.waffle.io/akkadotnet/akka.net.svg?label=help%20wanted&title=Issues%20Needing%20Help%20Now!)](http://waffle.io/akkadotnet/akka.net)
-[![Stories Up For Grabs](https://badge.waffle.io/akkadotnet/akka.net.svg?label=up%20for%20grabs&title=General Issues Up For Grabs)](http://waffle.io/akkadotnet/akka.net) +[![Stories Up For Grabs](https://badge.waffle.io/akkadotnet/akka.net.svg?label=up%20for%20grabs&title=General%20Issues%20Up%20For%20Grabs)](http://waffle.io/akkadotnet/akka.net) > *All contributions are welcome! Please consider the [issues categorized in the `Help!` column](http://waffle.io/akkadotnet/akka.net) first, as they are areas we could really use your help :)* diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 53c93ca2bc6..769655cc04e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,51 @@ +#### 1.3.0 August 11 2017 #### +**Feature Release for Akka.NET** +Akka.NET 1.3.0 is a major feature release that introduces the significant changes to Akka.NET and its runtime. + +**.NET Core and .NET Standard 1.6 Support** +This release introduces support for .NET Standard 1.6 for our core libraries and .NET Core 1.1 for the MultiNode Test Runner standalone executable. All packages for Akka.NET are dual-released under both .NET 4.5 and .NET Standard 1.6. + +As a side note: Akka.NET on .NET 4.5 is not wire compatible with Akka.NET on .NET Core; this is due to fundamental changes made to the base types in the CLR on .NET Core. It's a common problem facing many different serializers and networking libraries in .NET at the moment. You can use a X-plat serializer we've developed here: https://github.com/akkadotnet/akka.net/pull/2947 - please comment on that thread if you're considering building hybrid .NET and .NET Core clusters. + +**Akka.Persistence Released to Market** +Akka.Persistence has graduated from beta status to stable modules and its interfaces are now considered to be stable. We'll begin updating all of the Akka.Persistence plugins to stable and to add .NET Standard / .NET 4.5 support to each of them as well following this patch. + +**DocFx-based Documentation Site** +Documentation is now generated using DocFx and compiled from within the Akka.NET project rather than a separate documentation repository. + +**API Changes** +This release does **not** maintain wire format compatibility with the previous release (v1.2.3) inside Akka.Remote; primarily this is due to having to upgrade from Google Protobuf2 to Protobuf3 in order to add .NET Standard support, but we've also taken the liberty of making other serialization improvements while we're at it. So be advised that during an upgrade from 1.2.* to 1.3.* there will be periods of network disruption between nodes using different versions of the service. + +**Akka.Remote Performance Improvements** +Akka.Remote's throughput has been significantly increased. + +[See the full set of Akka.NET 1.3.0 fixes here](https://github.com/akkadotnet/akka.net/milestone/14). + +| COMMITS | LOC+ | LOC- | AUTHOR | +| --- | --- | --- | --- | +| 64 | 7109 | 2670 | Marc Piechura | +| 61 | 2420 | 6703 | Nick Chamberlain | +| 46 | 2316 | 10066 | Aaron Stannard | +| 42 | 56428 | 85473 | Alex Valuyskiy | +| 32 | 7924 | 9483 | ravengerUA | +| 31 | 17284 | 13592 | Bartosz Sypytkowski | +| 25 | 2527 | 1124 | Gregorius Soedharmo | +| 21 | 7810 | 1688 | zbynek001 | +| 11 | 1932 | 2167 | Sean Gilliam | +| 9 | 946 | 219 | Arjen Smits | +| 4 | 679 | 105 | alexvaluyskiy | +| 4 | 344 | 6 | Lealand Vettleson | +| 4 | 1644 | 2210 | Arkatufus | +| 3 | 32 | 6 | Lukas Rieger | +| 3 | 153 | 17 | Quartus Dev | +| 2 | 8 | 11 | Paweł Bańka | +| 2 | 4866 | 12678 | olegz | +| 2 | 1148 | 176 | Ismael Hamed | +| 1 | 62 | 5 | Mikhail Kantarovskiy | +| 1 | 4 | 2 | tstojecki | +| 1 | 22 | 2 | Maxim Cherednik | +| 1 | 1 | 1 | Sean Killeen | + #### 1.2.3 July 07 2017 #### **Maintenance Release for Akka.NET 1.2** diff --git a/build.cmd b/build.cmd index abf65d45ecc..3cb534eae56 100644 --- a/build.cmd +++ b/build.cmd @@ -1,37 +1 @@ -@echo off - -pushd %~dp0 - -SETLOCAL -SET CACHED_NUGET=%LocalAppData%\NuGet\NuGet.exe - -IF EXIST %CACHED_NUGET% goto copynuget -echo Downloading latest version of NuGet.exe... -IF NOT EXIST %LocalAppData%\NuGet md %LocalAppData%\NuGet -@powershell -NoProfile -ExecutionPolicy unrestricted -Command "$ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest 'https://dist.nuget.org/win-x86-commandline/v4.1.0/nuget.exe' -OutFile '%CACHED_NUGET%'" - -:copynuget -IF EXIST src\.nuget\nuget.exe goto restore -md src\.nuget -copy %CACHED_NUGET% src\.nuget\nuget.exe > nul - -:restore - -pushd %~dp0 - -src\.nuget\NuGet.exe install FAKE -ConfigFile src\.nuget\Nuget.Config -OutputDirectory src\packages -ExcludeVersion -Version 4.16.1 - -src\.nuget\NuGet.exe install NUnit.Console -ConfigFile src\.nuget\Nuget.Config -OutputDirectory src\packages\FAKE -ExcludeVersion -Version 3.2.1 -src\.nuget\NuGet.exe install xunit.runner.console -ConfigFile src\.nuget\Nuget.Config -OutputDirectory src\packages\FAKE -ExcludeVersion -Version 2.0.0 -src\.nuget\NuGet.exe install NBench.Runner -OutputDirectory src\packages -ExcludeVersion -Version 0.3.3 -src\.nuget\NuGet.exe install Microsoft.SourceBrowser -OutputDirectory src\packages -ExcludeVersion - -if not exist src\packages\SourceLink.Fake\tools\SourceLink.fsx ( - src\.nuget\nuget.exe install SourceLink.Fake -ConfigFile src\.nuget\Nuget.Config -OutputDirectory src\packages -ExcludeVersion -) -rem cls - -set encoding=utf-8 -src\packages\FAKE\tools\FAKE.exe build.fsx %* - -popd +PowerShell.exe -file "build.ps1" %* \ No newline at end of file diff --git a/build.fsx b/build.fsx index 208f840efc4..8b63b4de1dc 100644 --- a/build.fsx +++ b/build.fsx @@ -1,329 +1,194 @@ -#I @"src/packages/FAKE/tools" +#I @"tools/FAKE/tools" #r "FakeLib.dll" -#r "System.Xml.Linq" +#load "./buildIncremental.fsx" open System open System.IO open System.Text -open Fake -open Fake.FileUtils -open Fake.TaskRunnerHelper -open Fake.ProcessHelper - -cd __SOURCE_DIRECTORY__ - -//-------------------------------------------------------------------------------- -// Information about the project for Nuget and Assembly info files -//-------------------------------------------------------------------------------- +open System.Diagnostics +open Fake +open Fake.DotNetCli +open Fake.DocFxHelper +open Fake.Git -let product = "Akka.NET" -let authors = [ "Akka.NET Team" ] -let copyright = "Copyright © 2013-2017 Akka.NET Team" -let company = "Akka.NET Team" -let description = "Akka.NET is a port of the popular Java/Scala framework Akka to .NET" -let tags = ["akka";"actors";"actor";"model";"Akka";"concurrency"] +// Variables let configuration = "Release" -let toolDir = "tools" -let CloudCopyDir = toolDir @@ "CloudCopy" -let AzCopyDir = toolDir @@ "AzCopy" - -// Read release notes and version - -let parsedRelease = - File.ReadLines "RELEASE_NOTES.md" - |> ReleaseNotesHelper.parseReleaseNotes - -let envBuildNumber = System.Environment.GetEnvironmentVariable("BUILD_NUMBER") -let buildNumber = if String.IsNullOrWhiteSpace(envBuildNumber) then "0" else envBuildNumber - -let version = parsedRelease.AssemblyVersion + "." + buildNumber -let preReleaseVersion = version + "-beta" - -let isUnstableDocs = hasBuildParam "unstable" -let isPreRelease = hasBuildParam "nugetprerelease" -let release = if isPreRelease then ReleaseNotesHelper.ReleaseNotes.New(version, version + "-beta", parsedRelease.Notes) else parsedRelease +let solution = "./src/Akka.sln" -printfn "Assembly version: %s\nNuget version; %s\n" release.AssemblyVersion release.NugetVersion -//-------------------------------------------------------------------------------- // Directories +let toolsDir = __SOURCE_DIRECTORY__ @@ "tools" +let output = __SOURCE_DIRECTORY__ @@ "bin" +let outputTests = __SOURCE_DIRECTORY__ @@ "TestResults" +let outputPerfTests = __SOURCE_DIRECTORY__ @@ "PerfResults" +let outputBinaries = output @@ "binaries" +let outputNuGet = output @@ "nuget" +let outputMultiNode = outputTests @@ "multinode" +let outputBinariesNet45 = outputBinaries @@ "net45" +let outputBinariesNetStandard = outputBinaries @@ "netstandard1.6" + +let buildNumber = environVarOrDefault "BUILD_NUMBER" "0" +let preReleaseVersionSuffix = (if (not (buildNumber = "0")) then (buildNumber) else "") + "-beta" +let versionSuffix = + match (getBuildParam "nugetprerelease") with + | "dev" -> preReleaseVersionSuffix + | _ -> "" + +let releaseNotes = + File.ReadLines "./RELEASE_NOTES.md" + |> ReleaseNotesHelper.parseReleaseNotes -let binDir = "bin" -let testOutput = FullName "TestResults" -let perfOutput = FullName "PerfResults" - -let nugetDir = binDir @@ "nuget" -let workingDir = binDir @@ "build" -let libDir = workingDir @@ @"lib\net45\" -let nugetExe = FullName @"src\.nuget\NuGet.exe" -let docDir = "bin" @@ "doc" -let sourceBrowserDocsDir = binDir @@ "sourcebrowser" -let msdeployPath = "C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe" - -open Fake.RestorePackageHelper -Target "RestorePackages" (fun _ -> - "./src/Akka.sln" - |> RestoreMSSolutionPackages (fun p -> - { p with - OutputPath = "./src/packages" - Retries = 4 }) - ) - -//-------------------------------------------------------------------------------- -// Clean build results - -Target "Clean" <| fun _ -> - DeleteDir binDir - -//-------------------------------------------------------------------------------- -// Generate AssemblyInfo files with the version for release notes - -open AssemblyInfoFile - -Target "AssemblyInfo" <| fun _ -> - CreateCSharpAssemblyInfoWithConfig "src/SharedAssemblyInfo.cs" [ - Attribute.Company company - Attribute.Copyright copyright - Attribute.Trademark "" - Attribute.Version version - Attribute.FileVersion version ] <| AssemblyInfoFileConfig(false) - - for file in !! "src/**/AssemblyInfo.fs" do - let title = - file - |> Path.GetDirectoryName - |> Path.GetDirectoryName - |> Path.GetFileName - - CreateFSharpAssemblyInfo file [ - Attribute.Title title - Attribute.Product product - Attribute.Description description - Attribute.Copyright copyright - Attribute.Company company - Attribute.ComVisible false - Attribute.CLSCompliant true - Attribute.Version version - Attribute.FileVersion version ] - - -//-------------------------------------------------------------------------------- -// Build the solution - -Target "Build" <| fun _ -> - - !!"src/Akka.sln" - |> MSBuildRelease "" "Rebuild" - |> ignore - -//-------------------------------------------------------------------------------- -// Build the docs -Target "Docs" <| fun _ -> - !! "documentation/akkadoc.shfbproj" - |> MSBuildRelease "" "Rebuild" - |> ignore - -//-------------------------------------------------------------------------------- -// Push DOCs content to Windows Azure blob storage -Target "AzureDocsDeploy" (fun _ -> - let rec pushToAzure docDir azureUrl container azureKey trialsLeft = - let tracing = enableProcessTracing - enableProcessTracing <- false - let arguments = sprintf "/Source:%s /Dest:%s /DestKey:%s /S /Y /SetContentType" (Path.GetFullPath docDir) (azureUrl @@ container) azureKey - tracefn "Pushing docs to %s. Attempts left: %d" (azureUrl) trialsLeft - try - - let result = ExecProcess(fun info -> - info.FileName <- AzCopyDir @@ "AzCopy.exe" - info.Arguments <- arguments) (TimeSpan.FromMinutes 120.0) //takes a very long time to upload - if result <> 0 then failwithf "Error during AzCopy.exe upload to azure." - with exn -> - if (trialsLeft > 0) then (pushToAzure docDir azureUrl container azureKey (trialsLeft-1)) - else raise exn - let canPush = hasBuildParam "azureKey" && hasBuildParam "azureUrl" - if (canPush) then - printfn "Uploading API docs to Azure..." - let azureUrl = getBuildParam "azureUrl" - let azureKey = (getBuildParam "azureKey") + "==" //hack, because it looks like FAKE arg parsing chops off the "==" that gets tacked onto the end of each Azure storage key - if(isUnstableDocs) then - pushToAzure docDir azureUrl "unstable" azureKey 3 - if(not isUnstableDocs) then - pushToAzure docDir azureUrl "stable" azureKey 3 - pushToAzure docDir azureUrl release.NugetVersion azureKey 3 - if(not canPush) then - printfn "Missing required parameters to push docs to Azure. Run build HelpDocs to find out!" - +Target "Clean" (fun _ -> + ActivateFinalTarget "KillCreatedProcesses" + + CleanDir output + CleanDir outputTests + CleanDir outputPerfTests + CleanDir outputBinaries + CleanDir outputNuGet + CleanDir outputMultiNode + CleanDir outputBinariesNet45 + CleanDir outputBinariesNetStandard + CleanDir "docs/_site" + + CleanDirs !! "./**/bin" + CleanDirs !! "./**/obj" ) -Target "PublishDocs" DoNothing +Target "AssemblyInfo" (fun _ -> + XmlPokeInnerText "./src/common.props" "//Project/PropertyGroup/VersionPrefix" releaseNotes.AssemblyVersion + XmlPokeInnerText "./src/common.props" "//Project/PropertyGroup/PackageReleaseNotes" (releaseNotes.Notes |> String.concat "\n") +) -//-------------------------------------------------------------------------------- -// Build the SourceBrowser docs -//-------------------------------------------------------------------------------- -Target "GenerateSourceBrowser" <| (fun _ -> - DeleteDir sourceBrowserDocsDir +Target "RestorePackages" (fun _ -> + let additionalArgs = if versionSuffix.Length > 0 then [sprintf "/p:VersionSuffix=%s" versionSuffix] else [] - let htmlGeneratorPath = "src/packages/Microsoft.SourceBrowser/tools/HtmlGenerator.exe" - let arguments = sprintf "/out:%s %s" sourceBrowserDocsDir "src/Akka.sln" - printfn "Using SourceBrowser: %s %s" htmlGeneratorPath arguments - - let result = ExecProcess(fun info -> - info.FileName <- htmlGeneratorPath - info.Arguments <- arguments) (System.TimeSpan.FromMinutes 20.0) - - if result <> 0 then failwithf "SourceBrowser failed. %s %s" htmlGeneratorPath arguments + DotNetCli.Restore + (fun p -> + { p with + Project = solution + NoCache = false + AdditionalArgs = additionalArgs }) ) -//-------------------------------------------------------------------------------- -// Publish the SourceBrowser docs -//-------------------------------------------------------------------------------- -Target "PublishSourceBrowser" <| (fun _ -> - let canPublish = hasBuildParam "publishsettings" - if (canPublish) then - let sourceBrowserPublishSettingsPath = getBuildParam "publishsettings" - let arguments = sprintf "-verb:sync -source:contentPath=\"%s\" -dest:contentPath=sourcebrowser,publishSettings=\"%s\"" (Path.GetFullPath sourceBrowserDocsDir) sourceBrowserPublishSettingsPath - printfn "Using MSDeploy: %s %s" msdeployPath arguments - - let result = ExecProcess(fun info -> - info.FileName <- msdeployPath - info.Arguments <- arguments) (System.TimeSpan.FromMinutes 30.0) //takes a long time to upload - - if result <> 0 then failwithf "MSDeploy failed. %s %s" msdeployPath arguments - else - printfn "Missing required parameter to publish SourceBrowser docs. Run build HelpSourceBrowserDocs to find out!" +Target "Build" (fun _ -> + let additionalArgs = if versionSuffix.Length > 0 then [sprintf "/p:VersionSuffix=%s" versionSuffix] else [] + + DotNetCli.Build + (fun p -> + { p with + Project = solution + Configuration = configuration + AdditionalArgs = additionalArgs }) ) //-------------------------------------------------------------------------------- -// Copy the build output to bin directory +// Tests targets //-------------------------------------------------------------------------------- -Target "CopyOutput" <| fun _ -> +module internal ResultHandling = + let (|OK|Failure|) = function + | 0 -> OK + | x -> Failure x + + let buildErrorMessage = function + | OK -> None + | Failure errorCode -> + Some (sprintf "xUnit2 reported an error (Error Code %d)" errorCode) + + let failBuildWithMessage = function + | DontFailBuild -> traceError + | _ -> (fun m -> raise(FailedTestsException m)) + + let failBuildIfXUnitReportedError errorLevel = + buildErrorMessage + >> Option.iter (failBuildWithMessage errorLevel) + +open BuildIncremental.IncrementalTests + +Target "RunTests" (fun _ -> + ActivateFinalTarget "KillCreatedProcesses" + let projects = + match getBuildParamOrDefault "incremental" "" with + | "true" -> log "The following test projects would be run under Incremental Test config..." + getIncrementalUnitTests() |> Seq.map (fun x -> printfn "\t%s" x; x) + | "experimental" -> log "The following test projects would be run under Incremental Test config..." + getIncrementalUnitTests() |> Seq.iter log + getUnitTestProjects() + | _ -> log "All test projects will be run..." + getUnitTestProjects() - let copyOutput project = - let src = "src" @@ project @@ @"bin/Release/" - let dst = binDir @@ project - CopyDir dst src allFiles - [ "core/Akka" - "core/Akka.FSharp" - "core/Akka.TestKit" - "core/Akka.Remote" - "core/Akka.Remote.TestKit" - "core/Akka.Cluster" - "core/Akka.Cluster.TestKit" - "core/Akka.MultiNodeTestRunner" - "core/Akka.Persistence" - "core/Akka.Persistence.FSharp" - "core/Akka.Persistence.TestKit" - "core/Akka.Persistence.Query" - "core/Akka.Streams" - "core/Akka.Streams.TestKit" - "contrib/dependencyinjection/Akka.DI.Core" - "contrib/dependencyinjection/Akka.DI.TestKit" - "contrib/testkits/Akka.TestKit.Xunit" - "contrib/testkits/Akka.TestKit.Xunit2" - "contrib/serializers/Akka.Serialization.Wire" - "contrib/serializers/Akka.Serialization.Hyperion" - "contrib/cluster/Akka.Cluster.Tools" - "contrib/cluster/Akka.Cluster.Sharding" - "contrib/cluster/Akka.DistributedData" - "contrib/cluster/Akka.DistributedData.LightningDB" - ] - |> List.iter copyOutput - -Target "BuildRelease" DoNothing - - + let runSingleProject project = + let result = ExecProcess(fun info -> + info.FileName <- "dotnet" + info.WorkingDirectory <- (Directory.GetParent project).FullName + info.Arguments <- (sprintf "xunit -f net452 -c Release -nobuild -parallel none -teamcity -xml %s_xunit.xml" (outputTests @@ fileNameWithoutExt project))) (TimeSpan.FromMinutes 30.) + + ResultHandling.failBuildIfXUnitReportedError TestRunnerErrorLevel.DontFailBuild result -//-------------------------------------------------------------------------------- -// Tests targets -//-------------------------------------------------------------------------------- + // dotnet process will be killed by ExecProcess (or throw if can't) ' + // but per https://github.com/xunit/xunit/issues/1338 xunit.console may not + killProcess "xunit.console" + killProcess "dotnet" -//-------------------------------------------------------------------------------- -// Filter out assemblies which can't run on Linux, Mono, .NET Core, etc... - -open Fake.EnvironmentHelper -let filterPlatformSpecificAssemblies (assembly:string) = - match assembly with - | assembly when (assembly.Contains("Sqlite") && isMono) -> false - | assembly when (assembly.Contains(".API") && isMono) -> false - | assembly when (assembly.Contains("Akka.Remote.TestKit.Tests") && isMono) -> false - | assembly when (assembly.Contains("Akka.Persistence.TestKit.Tests") && isMono) -> false - | assembly when (assembly.Contains("Akka.Streams.Tests.TCK") && isMono) -> false - | _ -> true + CreateDir outputTests + projects |> Seq.iter (runSingleProject) -//-------------------------------------------------------------------------------- -// Clean test output +) -Target "CleanTests" <| fun _ -> - DeleteDir testOutput -//-------------------------------------------------------------------------------- -// Run tests - -open Fake.Testing -Target "RunTests" <| fun _ -> - let xunitTestAssemblies = Seq.filter filterPlatformSpecificAssemblies ( - !! "src/**/bin/Release/*.Tests.dll" - // Akka.Streams.Tests is referencing Akka.Streams.TestKit.Tests - -- "src/**/Akka.Streams.Tests/bin/Release/Akka.Streams.TestKit.Tests.dll" - // Akka.Streams.Tests.Performance is referencing Akka.Streams.Tests and Akka.Streams.TestKit.Tests - -- "src/**/Akka.Streams.Tests.Performance/bin/Release/*.Tests.dll") - - let nunitTestAssemblies = Seq.filter filterPlatformSpecificAssemblies (!! "src/**/bin/Release/Akka.Streams.Tests.TCK.dll") - - // Debug output - xunitTestAssemblies |> Seq.iter (printfn "Executing: %s") - - mkdir testOutput - - let xunitToolPath = findToolInSubPath "xunit.console.exe" "src/packages/FAKE/xunit.runner.console*/tools" - let nunitToolPath = findToolInSubPath "nunit3-console.exe" "src/packages/FAKE/NUnit.ConsoleRunner/tools" - - printfn "Using XUnit runner: %s" xunitToolPath - let runSingleAssembly assembly = - let assemblyName = Path.GetFileNameWithoutExtension(assembly) - xUnit2 - (fun p -> { p with XmlOutputPath = Some (testOutput @@ (assemblyName + "_xunit.xml")); HtmlOutputPath = Some (testOutput @@ (assemblyName + "_xunit.html")); ToolPath = xunitToolPath; TimeOut = System.TimeSpan.FromMinutes 30.0; Parallel = ParallelMode.NoParallelization; NoAppDomain = true; ForceTeamCity = true; }) - (Seq.singleton assembly) - - xunitTestAssemblies |> Seq.iter (runSingleAssembly) - - let runNunitSingleAssembly assembly = - let assemblyName = Path.GetFileNameWithoutExtension(assembly) - NUnit3 - (fun p -> { p with ToolPath = nunitToolPath; WorkingDir = testOutput; TeamCity = true;}) - (Seq.singleton assembly) +Target "RunTestsNetCore" (fun _ -> + ActivateFinalTarget "KillCreatedProcesses" + let projects = + match getBuildParamOrDefault "incremental" "" with + | "true" -> log "The following test projects would be run under Incremental Test config..." + getIncrementalUnitTests() |> Seq.map (fun x -> printfn "\t%s" x; x) + | "experimental" -> log "The following test projects would be run under Incremental Test config..." + getIncrementalUnitTests() |> Seq.iter log + getUnitTestProjects() + | _ -> log "All test projects will be run..." + getUnitTestProjects() + + let runSingleProject project = + let result = ExecProcess(fun info -> + info.FileName <- "dotnet" + info.WorkingDirectory <- (Directory.GetParent project).FullName + info.Arguments <- (sprintf "xunit -f netcoreapp1.1 -c Release -parallel none -teamcity -xml %s_xunit_netcore.xml" (outputTests @@ fileNameWithoutExt project))) (TimeSpan.FromMinutes 30.) - printfn "Using NUnit runner: %s" nunitToolPath - nunitTestAssemblies |> Seq.iter (runNunitSingleAssembly) + ResultHandling.failBuildIfXUnitReportedError TestRunnerErrorLevel.DontFailBuild result + // dotnet process will be killed by FAKE.ExecProcess (or throw if can't) + // but per https://github.com/xunit/xunit/issues/1338 xunit.console may not be killed + killProcess "xunit.console" + killProcess "dotnet" -(* Debug helper for troubleshooting an issue we had when we were running multi-node tests multiple times *) -Target "PrintMultiNodeTests" <| fun _ -> - let testSearchPath = - let assemblyFilter = getBuildParamOrDefault "spec-assembly" String.Empty - sprintf "src/**/bin/Release/*%s*.Tests.MultiNode.dll" assemblyFilter - (!! testSearchPath) |> Seq.iter (printfn "%s") - + CreateDir outputTests + projects |> Seq.iter (runSingleProject) +) +Target "MultiNodeTests" (fun _ -> + ActivateFinalTarget "KillCreatedProcesses" + let multiNodeTestPath = findToolInSubPath "Akka.MultiNodeTestRunner.exe" (currentDirectory @@ "src" @@ "core" @@ "Akka.MultiNodeTestRunner" @@ "bin" @@ "Release" @@ "net452") -Target "MultiNodeTests" <| fun _ -> - mkdir testOutput - let multiNodeTestPath = findToolInSubPath "Akka.MultiNodeTestRunner.exe" (currentDirectory @@ "bin" @@ "core" @@ "Akka.MultiNodeTestRunner*") - let multiNodeTestAssemblies = !! "src/**/bin/Release/Akka.Remote.Tests.MultiNode.dll" ++ - "src/**/bin/Release/Akka.Cluster.Tests.MultiNode.dll" ++ - "src/**/bin/Release/Akka.Cluster.Tools.Tests.MultiNode.dll" ++ - "src/**/bin/Release/Akka.Cluster.Sharding.Tests.MultiNode.dll" ++ - "src/**/bin/Release/Akka.DistributedData.Tests.MultiNode.dll" + let multiNodeTestAssemblies = + match getBuildParamOrDefault "incremental" "" with + | "true" -> log "The following test projects would be run under Incremental Test config..." + getIncrementalMNTRTests() |> Seq.map (fun x -> printfn "\t%s" x; x) + | "experimental" -> log "The following MNTR specs would be run under Incremental Test config..." + getIncrementalMNTRTests() |> Seq.iter log + getAllMntrTestAssemblies() + | _ -> log "All test projects will be run" + getAllMntrTestAssemblies() printfn "Using MultiNodeTestRunner: %s" multiNodeTestPath let runMultiNodeSpec assembly = let spec = getBuildParam "spec" - let args = new StringBuilder() + let args = StringBuilder() |> append assembly + |> append "-Dmultinode.teamcity=true" |> append "-Dmultinode.enable-filesink=on" - |> append (sprintf "-Dmultinode.output-directory=\"%s\"" testOutput) + |> append (sprintf "-Dmultinode.output-directory=\"%s\"" outputMultiNode) |> appendIfNotNullOrEmpty spec "-Dmultinode.spec=" |> toText @@ -334,22 +199,68 @@ Target "MultiNodeTests" <| fun _ -> if result <> 0 then failwithf "MultiNodeTestRunner failed. %s %s" multiNodeTestPath args multiNodeTestAssemblies |> Seq.iter (runMultiNodeSpec) +) + +Target "MultiNodeTestsNetCore" (fun _ -> + ActivateFinalTarget "KillCreatedProcesses" + let multiNodeTestPath = findToolInSubPath "Akka.MultiNodeTestRunner.dll" (currentDirectory @@ "src" @@ "core" @@ "Akka.MultiNodeTestRunner" @@ "bin" @@ "Release" @@ "netcoreapp1.1" @@ "win7-x64" @@ "publish") + + let multiNodeTestAssemblies = + match getBuildParamOrDefault "incremental" "" with + | "true" -> log "The following test projects would be run under Incremental Test config..." + getIncrementalNetCoreMNTRTests() |> Seq.map (fun x -> printfn "\t%s" x; x) + | "experimental" -> log "The following MNTR specs would be run under Incremental Test config..." + getIncrementalNetCoreMNTRTests() |> Seq.iter log + getAllMntrTestNetCoreAssemblies() + | _ -> log "All test projects will be run" + getAllMntrTestNetCoreAssemblies() + + printfn "Using MultiNodeTestRunner: %s" multiNodeTestPath + + let runMultiNodeSpec assembly = + match assembly with + | null -> () + | _ -> + let spec = getBuildParam "spec" + + let args = StringBuilder() + |> append multiNodeTestPath + |> append assembly + |> append "-Dmultinode.teamcity=true" + |> append "-Dmultinode.enable-filesink=on" + |> append (sprintf "-Dmultinode.output-directory=\"%s\"" outputMultiNode) + |> append "-Dmultinode.platform=netcore" + |> appendIfNotNullOrEmpty spec "-Dmultinode.spec=" + |> toText + + let result = ExecProcess(fun info -> + info.FileName <- "dotnet" + info.WorkingDirectory <- (Path.GetDirectoryName (FullName multiNodeTestPath)) + info.Arguments <- args) (System.TimeSpan.FromMinutes 60.0) (* This is a VERY long running task. *) + if result <> 0 then failwithf "MultiNodeTestRunner failed. %s %s" multiNodeTestPath args + + multiNodeTestAssemblies |> Seq.iter (runMultiNodeSpec) +) -//-------------------------------------------------------------------------------- -// NBench targets -//-------------------------------------------------------------------------------- Target "NBench" <| fun _ -> - let testSearchPath = - let assemblyFilter = getBuildParamOrDefault "spec-assembly" String.Empty - sprintf "src/**/bin/Release/*%s*.Tests.Performance.dll" assemblyFilter + ActivateFinalTarget "KillCreatedProcesses" + CleanDir outputPerfTests - mkdir perfOutput - let nbenchTestPath = findToolInSubPath "NBench.Runner.exe" "src/packges/NBench.Runner*" - let nbenchTestAssemblies = Seq.filter filterPlatformSpecificAssemblies (!! testSearchPath) + let nbenchTestPath = findToolInSubPath "NBench.Runner.exe" (toolsDir @@ "NBench.Runner*") printfn "Using NBench.Runner: %s" nbenchTestPath + let nbenchTestAssemblies = + match getBuildParamOrDefault "incremental" "" with + | "true" -> log "The following test projects would be run under Incremental Test config..." + getIncrementalPerfTests() |> Seq.map (fun x -> printfn "\t%s" x; x) + | "experimental" -> log "The following test projects would be run under Incremental Test config..." + getIncrementalPerfTests() |> Seq.iter log + getAllPerfTestAssemblies() + | _ -> getAllPerfTestAssemblies() + let runNBench assembly = - let spec = getBuildParam "spec" + let includes = getBuildParam "include" + let excludes = getBuildParam "exclude" let teamcityStr = (getBuildParam "teamcity") let enableTeamCity = match teamcityStr with @@ -357,12 +268,14 @@ Target "NBench" <| fun _ -> | "" -> false | _ -> bool.Parse teamcityStr - let args = new StringBuilder() + let args = StringBuilder() |> append assembly - |> append (sprintf "output-directory=\"%s\"" perfOutput) + |> append (sprintf "output-directory=\"%s\"" outputPerfTests) |> append (sprintf "concurrent=\"%b\"" true) |> append (sprintf "trace=\"%b\"" true) |> append (sprintf "teamcity=\"%b\"" enableTeamCity) + |> appendIfNotNullOrEmpty includes "include=" + |> appendIfNotNullOrEmpty excludes "include=" |> toText let result = ExecProcess(fun info -> @@ -371,202 +284,209 @@ Target "NBench" <| fun _ -> info.Arguments <- args) (System.TimeSpan.FromMinutes 45.0) (* Reasonably long-running task. *) if result <> 0 then failwithf "NBench.Runner failed. %s %s" nbenchTestPath args - nbenchTestAssemblies |> Seq.iter (runNBench) - -//-------------------------------------------------------------------------------- -// Clean NBench output -Target "CleanPerf" <| fun _ -> - DeleteDir perfOutput - + nbenchTestAssemblies |> Seq.iter runNBench //-------------------------------------------------------------------------------- // Nuget targets //-------------------------------------------------------------------------------- -module Nuget = - // add Akka dependency for other projects - let getAkkaDependency project = - match project with - | "Akka" -> [] - | "Akka.Cluster" -> ["Akka.Remote", release.NugetVersion] - | "Akka.Cluster.TestKit" -> ["Akka.Remote.TestKit", release.NugetVersion; "Akka.Cluster", release.NugetVersion] - | "Akka.Cluster.Sharding" -> ["Akka.Cluster.Tools", release.NugetVersion; "Akka.Persistence", preReleaseVersion] - | "Akka.Cluster.Tools" -> ["Akka.Cluster", release.NugetVersion] - | "Akka.MultiNodeTestRunner" -> [] // all binaries for the multinodetest runner have to be included locally - | "Akka.Persistence.TestKit" -> ["Akka.Persistence", preReleaseVersion; "Akka.TestKit.Xunit2", release.NugetVersion] - | "Akka.Persistence.Query" -> ["Akka.Persistence", preReleaseVersion; "Akka.Streams", release.NugetVersion] - | "Akka.Persistence.Query.Sql" -> ["Akka.Persistence.Query", preReleaseVersion; "Akka.Persistence.Sql.Common", preReleaseVersion] - | "Akka.Persistence.Sql.TestKit" -> ["Akka.Persistence.Query.Sql", preReleaseVersion; "Akka.Persistence.TestKit", preReleaseVersion; "Akka.Streams.TestKit", release.NugetVersion] - | persistence when (persistence.Contains("Sql") && not (persistence.Equals("Akka.Persistence.Sql.Common"))) -> ["Akka.Persistence.Sql.Common", preReleaseVersion] - | persistence when (persistence.StartsWith("Akka.Persistence.")) -> ["Akka.Persistence", preReleaseVersion] - | "Akka.DI.TestKit" -> ["Akka.DI.Core", release.NugetVersion; "Akka.TestKit.Xunit2", release.NugetVersion] - | testkit when testkit.StartsWith("Akka.TestKit.") -> ["Akka.TestKit", release.NugetVersion] - | "Akka.Remote.TestKit" -> ["Akka.Remote", release.NugetVersion; "Akka.TestKit.Xunit2", release.NugetVersion;] - | "Akka.Streams" -> ["Akka", release.NugetVersion] - | "Akka.Streams.TestKit" -> ["Akka.Streams", release.NugetVersion; "Akka.TestKit", release.NugetVersion] - | _ -> ["Akka", release.NugetVersion] - - // used to add -pre suffix to pre-release packages - let getProjectVersion project = - match project with - | "Akka.Serialization.Wire" -> preReleaseVersion - | "Akka.Serialization.Hyperion" -> preReleaseVersion - | "Akka.Cluster.Sharding" -> preReleaseVersion - | persistence when persistence.StartsWith("Akka.Persistence") -> preReleaseVersion - | "Akka.DistributedData" -> preReleaseVersion - | "Akka.DistributedData.LightningDB" -> preReleaseVersion - | _ -> release.NugetVersion - -open Nuget - -//-------------------------------------------------------------------------------- -// Clean nuget directory - -Target "CleanNuget" <| fun _ -> - CleanDir nugetDir +let overrideVersionSuffix (project:string) = + match project with + | p when p.Contains("Akka.Serialization.Wire") -> preReleaseVersionSuffix + | p when p.Contains("Akka.Serialization.Hyperion") -> preReleaseVersionSuffix + | p when p.Contains("Akka.Cluster.Sharding") -> preReleaseVersionSuffix + | p when p.Contains("Akka.DistributedData") -> preReleaseVersionSuffix + | p when p.Contains("Akka.DistributedData.LightningDB") -> preReleaseVersionSuffix + | _ -> versionSuffix + +Target "CreateNuget" (fun _ -> + let projects = !! "src/**/Akka.csproj" + ++ "src/**/Akka.Cluster.csproj" + ++ "src/**/Akka.Cluster.TestKit.csproj" + ++ "src/**/Akka.Cluster.Tools.csproj" + ++ "src/**/Akka.Cluster.Sharding.csproj" + ++ "src/**/Akka.DistributedData.csproj" + ++ "src/**/Akka.DistributedData.LightningDB.csproj" + ++ "src/**/Akka.Persistence.csproj" + ++ "src/**/Akka.Persistence.Query.csproj" + ++ "src/**/Akka.Persistence.TestKit.csproj" + ++ "src/**/Akka.Persistence.Query.Sql.csproj" + ++ "src/**/Akka.Persistence.Sql.Common.csproj" + ++ "src/**/Akka.Persistence.Sql.TestKit.csproj" + ++ "src/**/Akka.Persistence.Sqlite.csproj" + ++ "src/**/Akka.Remote.csproj" + ++ "src/**/Akka.Remote.TestKit.csproj" + ++ "src/**/Akka.Streams.csproj" + ++ "src/**/Akka.Streams.TestKit.csproj" + ++ "src/**/Akka.TestKit.csproj" + ++ "src/**/Akka.TestKit.Xunit2.csproj" + ++ "src/**/Akka.DI.Core.csproj" + ++ "src/**/Akka.DI.TestKit.csproj" + ++ "src/**/Akka.Serialization.Hyperion.csproj" + ++ "src/**/Akka.Serialization.TestKit.csproj" + ++ "src/**/Akka.Remote.Transport.Helios.csproj" + + let runSingleProject project = + DotNetCli.Pack + (fun p -> + { p with + Project = project + Configuration = configuration + AdditionalArgs = ["--include-symbols"] + VersionSuffix = overrideVersionSuffix project + OutputPath = outputNuGet }) + + projects |> Seq.iter (runSingleProject) +) +open Fake.TemplateHelper +Target "PublishMntr" (fun _ -> + let executableProjects = !! "./src/**/Akka.MultiNodeTestRunner.csproj" + + // Windows .NET 4.5.2 + executableProjects |> Seq.iter (fun project -> + DotNetCli.Restore + (fun p -> + { p with + Project = project + AdditionalArgs = ["-r win7-x64"; sprintf "/p:VersionSuffix=%s" versionSuffix] }) + ) + + // Windows .NET 4.5.2 + executableProjects |> Seq.iter (fun project -> + DotNetCli.Publish + (fun p -> + { p with + Project = project + Configuration = configuration + Runtime = "win7-x64" + Framework = "net452" + VersionSuffix = versionSuffix })) + + // Windows .NET Core + executableProjects |> Seq.iter (fun project -> + DotNetCli.Publish + (fun p -> + { p with + Project = project + Configuration = configuration + Runtime = "win7-x64" + Framework = "netcoreapp1.1" + VersionSuffix = versionSuffix })) +) -//-------------------------------------------------------------------------------- -// Pack nuget for all projects -// Publish to nuget.org if nugetkey is specified - -let createNugetPackages _ = - let removeDir dir = - let del _ = - DeleteDir dir - not (directoryExists dir) - runWithRetries del 3 |> ignore - - let getReleaseFiles project releaseDir = - match project with - | "Akka.MultiNodeTestRunner" -> // because the MNTR is an exe, all of its dlls have to be available in the same working directory when it executes - !! (releaseDir @@ "*.dll") - ++ (releaseDir @@ "*.exe") - ++ (releaseDir @@ "*.pdb") - ++ (releaseDir @@ "*.xml") - | _ -> - !! (releaseDir @@ project + ".dll") - ++ (releaseDir @@ project + ".exe") - ++ (releaseDir @@ project + ".pdb") - ++ (releaseDir @@ project + ".xml") - - let getExternalPackages project packagesFile = - match project with - | "Akka.MultiNodeTestRunner" -> [] // because the MNTR is an exe, all of its dlls have to be available in the same working directory when it executes - | _ -> if (fileExists packagesFile) then (getDependencies packagesFile) else [] - - ensureDirectory nugetDir - for nuspec in !! "src/**/*.nuspec" do - printfn "Creating nuget packages for %s" nuspec - - CleanDir workingDir - - let project = Path.GetFileNameWithoutExtension nuspec - let projectDir = Path.GetDirectoryName nuspec - let projectFile = (!! (projectDir @@ project + ".*sproj")) |> Seq.head - let releaseDir = projectDir @@ @"bin\Release" - let packages = projectDir @@ "packages.config" - let packageDependencies = getExternalPackages project packages - let dependencies = packageDependencies @ getAkkaDependency project - let releaseVersion = getProjectVersion project - - let pack outputDir symbolPackage = - NuGetHelper.NuGet - (fun p -> - { p with - Description = description - Authors = authors - Copyright = copyright - Project = project - Properties = ["Configuration", "Release"] - ReleaseNotes = release.Notes |> String.concat "\n" - Version = releaseVersion - Tags = tags |> String.concat " " - OutputPath = outputDir - WorkingDir = workingDir - SymbolPackage = symbolPackage - Dependencies = dependencies }) - nuspec - - // Copy dll, pdb and xml to libdir = workingDir/lib/net45/ - ensureDirectory libDir - getReleaseFiles project releaseDir - |> CopyFiles libDir - - // Copy all src-files (.cs and .fs files) to workingDir/src - let nugetSrcDir = workingDir @@ @"src/" - // CreateDir nugetSrcDir - - let isCs = hasExt ".cs" - let isFs = hasExt ".fs" - let isAssemblyInfo f = (filename f).Contains("AssemblyInfo") - let isSrc f = (isCs f || isFs f) && not (isAssemblyInfo f) - CopyDir nugetSrcDir projectDir isSrc - - //Remove workingDir/src/obj and workingDir/src/bin - removeDir (nugetSrcDir @@ "obj") - removeDir (nugetSrcDir @@ "bin") +Target "CreateMntrNuget" (fun _ -> + // uses the template file to create a temporary .nuspec file with the correct version + CopyFile "./src/core/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.nuspec" "./src/core/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.nuspec.template" + let commonPropsVersionPrefix = XMLRead true "./src/common.props" "" "" "//Project/PropertyGroup/VersionPrefix" |> Seq.head + let versionReplacement = List.ofSeq [ "@version@", commonPropsVersionPrefix + (if (not (versionSuffix = "")) then ("-" + versionSuffix) else "") ] + TemplateHelper.processTemplates versionReplacement [ "./src/core/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.nuspec" ] - // Create both normal nuget package and symbols nuget package. - // Uses the files we copied to workingDir and outputs to nugetdir - pack nugetDir NugetSymbolPackage.Nuspec - - removeDir workingDir - -let publishNugetPackages _ = - let rec publishPackage url accessKey trialsLeft packageFile = - let tracing = enableProcessTracing - enableProcessTracing <- false - let args p = - match p with - | (pack, key, "") -> sprintf "push \"%s\" %s" pack key - | (pack, key, url) -> sprintf "push \"%s\" %s -source %s" pack key url - - tracefn "Pushing %s Attempts left: %d" (FullName packageFile) trialsLeft - try - let result = ExecProcess (fun info -> - info.FileName <- nugetExe - info.WorkingDirectory <- (Path.GetDirectoryName (FullName packageFile)) - info.Arguments <- args (packageFile, accessKey,url)) (System.TimeSpan.FromMinutes 1.0) - enableProcessTracing <- tracing - if result <> 0 then failwithf "Error during NuGet symbol push. %s %s" nugetExe (args (packageFile, "key omitted",url)) - with exn -> - if (trialsLeft > 0) then (publishPackage url accessKey (trialsLeft-1) packageFile) - else raise exn - let shouldPushNugetPackages = hasBuildParam "nugetkey" - let shouldPushSymbolsPackages = (hasBuildParam "symbolspublishurl") && (hasBuildParam "symbolskey") + let executableProjects = !! "./src/**/Akka.MultiNodeTestRunner.csproj" - if (shouldPushNugetPackages || shouldPushSymbolsPackages) then - printfn "Pushing nuget packages" - if shouldPushNugetPackages then - let normalPackages= - !! (nugetDir @@ "*.nupkg") - -- (nugetDir @@ "*.symbols.nupkg") |> Seq.sortBy(fun x -> x.ToLower()) - for package in normalPackages do - try - publishPackage (getBuildParamOrDefault "nugetpublishurl" "") (getBuildParam "nugetkey") 3 package - with exn -> - printfn "%s" exn.Message - - if shouldPushSymbolsPackages then - let symbolPackages= !! (nugetDir @@ "*.symbols.nupkg") |> Seq.sortBy(fun x -> x.ToLower()) - for package in symbolPackages do - try - publishPackage (getBuildParam "symbolspublishurl") (getBuildParam "symbolskey") 3 package - with exn -> - printfn "%s" exn.Message - + executableProjects |> Seq.iter (fun project -> + DotNetCli.Pack + (fun p -> + { p with + Project = project + Configuration = configuration + AdditionalArgs = ["--include-symbols"] + VersionSuffix = overrideVersionSuffix project + OutputPath = outputNuGet } ) + ) + + DeleteFile "./src/core/Akka.MultiNodeTestRunner/Akka.MultiNodeTestRunner.nuspec" +) -Target "Nuget" <| fun _ -> - createNugetPackages() - publishNugetPackages() +Target "PublishNuget" (fun _ -> + let projects = !! "./bin/nuget/*.nupkg" -- "./bin/nuget/*.symbols.nupkg" + let apiKey = getBuildParamOrDefault "nugetkey" "" + let source = getBuildParamOrDefault "nugetpublishurl" "" + let symbolSource = getBuildParamOrDefault "symbolspublishurl" "" + let shouldPublishSymbolsPackages = not (symbolSource = "") + + if (not (source = "") && not (apiKey = "") && shouldPublishSymbolsPackages) then + let runSingleProject project = + DotNetCli.RunCommand + (fun p -> + { p with + TimeOut = TimeSpan.FromMinutes 10. }) + (sprintf "nuget push %s --api-key %s --source %s --symbol-source %s" project apiKey source symbolSource) + + projects |> Seq.iter (runSingleProject) + else if (not (source = "") && not (apiKey = "") && not shouldPublishSymbolsPackages) then + let runSingleProject project = + DotNetCli.RunCommand + (fun p -> + { p with + TimeOut = TimeSpan.FromMinutes 10. }) + (sprintf "nuget push %s --api-key %s --source %s" project apiKey source) + + projects |> Seq.iter (runSingleProject) +) -Target "CreateNuget" <| fun _ -> - createNugetPackages() +//-------------------------------------------------------------------------------- +// Serialization +//-------------------------------------------------------------------------------- +Target "Protobuf" <| fun _ -> + let protocPath = findToolInSubPath "protoc.exe" "src/packages/Google.Protobuf.Tools/tools/windows_x64" + + let protoFiles = [ + ("WireFormats.proto", "/src/core/Akka.Remote/Serialization/Proto/"); + ("ContainerFormats.proto", "/src/core/Akka.Remote/Serialization/Proto/"); + ("ContainerFormats.proto", "/src/core/Akka.Remote/Serialization/Proto/"); + ("SystemMessageFormats.proto", "/src/core/Akka.Remote/Serialization/Proto/"); + ("ClusterMessages.proto", "/src/core/Akka.Cluster/Serialization/Proto/"); + ("ClusterClientMessages.proto", "/src/contrib/cluster/Akka.Cluster.Tools/Client/Serialization/Proto/"); + ("DistributedPubSubMessages.proto", "/src/contrib/cluster/Akka.Cluster.Tools/PublishSubscribe/Serialization/Proto/"); + ("ClusterShardingMessages.proto", "/src/contrib/cluster/Akka.Cluster.Sharding/Serialization/Proto/"); + ("TestConductorProtocol.proto", "/src/core/Akka.Remote.TestKit/Proto/") ] + + printfn "Using proto.exe: %s" protocPath + + let runProtobuf assembly = + let protoName, destinationPath = assembly + let args = StringBuilder() + |> append (sprintf "-I=%s;%s" (__SOURCE_DIRECTORY__ @@ "/src/protobuf/") (__SOURCE_DIRECTORY__ @@ "/src/protobuf/common") ) + |> append (sprintf "--csharp_out=internal_access:%s" (__SOURCE_DIRECTORY__ @@ destinationPath)) + |> append "--csharp_opt=file_extension=.g.cs" + |> append (__SOURCE_DIRECTORY__ @@ "/src/protobuf" @@ protoName) + |> toText -Target "PublishNuget" <| fun _ -> - publishNugetPackages() + let result = ExecProcess(fun info -> + info.FileName <- protocPath + info.WorkingDirectory <- (Path.GetDirectoryName (FullName protocPath)) + info.Arguments <- args) (System.TimeSpan.FromMinutes 45.0) (* Reasonably long-running task. *) + if result <> 0 then failwithf "protoc failed. %s %s" protocPath args + + protoFiles |> Seq.iter (runProtobuf) +//-------------------------------------------------------------------------------- +// Documentation +//-------------------------------------------------------------------------------- +Target "DocFx" (fun _ -> + let docsExamplesSolution = "./docs/examples/DocsExamples.sln" + DotNetCli.Restore (fun p -> { p with Project = docsExamplesSolution }) + DotNetCli.Build (fun p -> { p with Project = docsExamplesSolution; Configuration = configuration }) + + let docsPath = "./docs" + + DocFx (fun p -> + { p with + Timeout = TimeSpan.FromMinutes 30.0; + WorkingDirectory = docsPath; + DocFxJson = docsPath @@ "docfx.json" }) +) +FinalTarget "KillCreatedProcesses" (fun _ -> + log "Killing processes started by FAKE:" + startedProcesses |> Seq.iter (fun (pid, _) -> logfn "%i" pid) + killAllCreatedProcesses() + log "Killing any remaining dotnet and xunit.console.exe processes:" + getProcessesByName "dotnet" |> Seq.iter (fun p -> logfn "pid: %i; name: %s" p.Id p.ProcessName) + killProcess "dotnet" + getProcessesByName "xunit.console" |> Seq.iter (fun p -> logfn "pid: %i; name: %s" p.Id p.ProcessName) + killProcess "xunit.console" +) //-------------------------------------------------------------------------------- // Help @@ -575,38 +495,27 @@ Target "PublishNuget" <| fun _ -> Target "Help" <| fun _ -> List.iter printfn [ "usage:" - "build [target]" + "/build [target]" "" " Targets for building:" " * Build Builds" " * Nuget Create and optionally publish nugets packages" " * RunTests Runs tests" - " * MultiNodeTests Runs the slower multiple node specifications" " * All Builds, run tests, creates and optionally publish nuget packages" "" " Other Targets" " * Help Display this help" - " * HelpNuget Display help about creating and pushing nuget packages" - " * HelpDocs Display help about creating and pushing API docs" - " * HelpMultiNodeTests Display help about running the multiple node specifications" ""] Target "HelpNuget" <| fun _ -> List.iter printfn [ "usage: " "build Nuget [nugetkey= [nugetpublishurl=]] " - " [symbolskey= symbolspublishurl=] " - " [nugetprerelease=]" - "" - "Arguments for Nuget target:" - " nugetprerelease= Creates a pre-release package." - " The version will be version-prefix" - " Example: nugetprerelease=dev =>" - " 0.6.3-dev1408191917" + " [symbolspublishurl=] " "" "In order to publish a nuget package, keys must be specified." "If a key is not specified the nuget packages will only be created on disk" - "After a build you can find them in bin/nuget" + "After a build you can find them in build/nuget" "" "For pushing nuget packages to nuget.org and symbols to symbolsource.org" "you need to specify nugetkey=" @@ -619,119 +528,42 @@ Target "HelpNuget" <| fun _ -> " symbolskey= symbolspublishurl= " "" "Examples:" - " build Nuget Build nuget packages to the bin/nuget folder" + " build Nuget Build nuget packages to the build/nuget folder" "" - " build Nuget nugetprerelease=dev Build pre-release nuget packages" + " build Nuget versionsuffix=beta1 Build nuget packages with the custom version suffix" "" " build Nuget nugetkey=123 Build and publish to nuget.org and symbolsource.org" "" - " build Nuget nugetprerelease=dev nugetkey=123 nugetpublishurl=http://abc" - " symbolskey=456 symbolspublishurl=http://xyz" - " Build and publish pre-release nuget packages to http://abc" - " and symbols packages to http://xyz" - ""] - -Target "HelpDocs" <| fun _ -> - List.iter printfn [ - "usage: " - "build Docs" - "Just builds the API docs for Akka.NET locally. Does not attempt to publish." - "" - "build PublishDocs azureKey= " - " azureUrl= " - " [unstable=true]" - "" - "Arguments for PublishDocs target:" - " azureKey= Azure blob storage key." - " Used to authenticate to the storage account." - "" - " azureUrl= Base URL for Azure storage container." - " FAKE will automatically set container" - " names based on build parameters." - "" - " [unstable=true] Indicates that we'll publish to an Azure" - " container named 'unstable'. If this param" - " is not present we'll publish to containers" - " 'stable' and the 'release.version'" - "" - "In order to publish documentation all of these values must be provided." - "Examples:" - " build PublishDocs azureKey=1s9HSAHA+..." - " azureUrl=http://fooaccount.blob.core.windows.net/docs" - " Build and publish docs to http://fooaccount.blob.core.windows.net/docs/stable" - " and http://fooaccount.blob.core.windows.net/docs/{release.version}" - "" - " build PublishDocs azureKey=1s9HSAHA+..." - " azureUrl=http://fooaccount.blob.core.windows.net/docs" - " unstable=true" - " Build and publish docs to http://fooaccount.blob.core.windows.net/docs/unstable" - ""] - - -Target "HelpSourceBrowserDocs" <| fun _ -> - List.iter printfn [ - "usage: " - "build GenerateSourceBrowser" - "Just generates the SourceBrowser docs for Akka.NET locally. Does not attempt to publish." - "" - "build PublishSourceBrowser publishsettings= " - "" - "Arguments for PublishSourceBrowser target:" - " publishsettings= Publish settings file." - "" - "In order to publish documentation all of these values must be provided." + " build Nuget nugetprerelease=dev nugetkey=123 nugetpublishurl=http://abcsymbolspublishurl=http://xyz" ""] - -Target "HelpMultiNodeTests" <| fun _ -> - List.iter printfn [ - "usage: " - "build MultiNodeTests [spec-assembly=]" - "Just runs the MultiNodeTests. Does not build the projects." - "" - "Arguments for MultiNodeTests target:" - " [spec-assembly=] Restrict which spec projects are run." - "" - " Alters the discovery filter to enable restricting which specs are run." - " If not supplied the filter used is '*.Tests.Multinode.Dll'" - " When supplied this is altered to '**.Tests.Multinode.Dll'" - ""] //-------------------------------------------------------------------------------- // Target dependencies //-------------------------------------------------------------------------------- +Target "BuildRelease" DoNothing +Target "All" DoNothing +Target "Nuget" DoNothing + // build dependencies -"Clean" ==> "AssemblyInfo" ==> "RestorePackages" ==> "Build" ==> "CopyOutput" ==> "BuildRelease" +"Clean" ==> "RestorePackages" ==> "Build" ==> "PublishMntr" ==> "BuildRelease" // tests dependencies -"CleanTests" ==> "RunTests" -"CleanTests" ==> "MultiNodeTests" - -// NBench dependencies -"CleanPerf" ==> "NBench" +// "RunTests" step doesn't require Clean ==> "RestorePackages" step +"Clean" ==> "RestorePackages" ==> "RunTestsNetCore" // nuget dependencies -"CleanNuget" ==> "CreateNuget" -"CleanNuget" ==> "BuildRelease" ==> "Nuget" +"Clean" ==> "RestorePackages" ==> "Build" ==> "PublishMntr" ==> "CreateMntrNuget" ==> "CreateNuget" +"CreateNuget" ==> "PublishNuget" ==> "Nuget" -//docs dependencies -"BuildRelease" ==> "Docs" ==> "AzureDocsDeploy" ==> "PublishDocs" +// docs +"BuildRelease" ==> "Docfx" -// SourceBrowser dependencies -"BuildRelease" ==> "GenerateSourceBrowser" ==> "PublishSourceBrowser" - -Target "All" DoNothing +// all "BuildRelease" ==> "All" "RunTests" ==> "All" +"RunTestsNetCore" ==> "All" "MultiNodeTests" ==> "All" "NBench" ==> "All" -"Nuget" ==> "All" - -Target "AllTests" DoNothing //used for Mono builds, due to Mono 4.0 bug with FAKE / NuGet https://github.com/fsharp/fsharp/issues/427 -"BuildRelease" ==> "AllTests" -"RunTests" ==> "AllTests" -"MultiNodeTests" ==> "AllTests" - -Target "RunTestsNetCore" DoNothing RunTargetOrDefault "Help" diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 00000000000..d3c5a772a0c --- /dev/null +++ b/build.ps1 @@ -0,0 +1,176 @@ +<# +.SYNOPSIS +This is a Powershell script to bootstrap a Fake build. +.DESCRIPTION +This Powershell script will download NuGet if missing, restore NuGet tools (including Fake) +and execute your Fake build script with the parameters you provide. +.PARAMETER Target +The build script target to run. +.PARAMETER Configuration +The build configuration to use. +.PARAMETER Verbosity +Specifies the amount of information to be displayed. +.PARAMETER WhatIf +Performs a dry run of the build script. +No tasks will be executed. +.PARAMETER ScriptArgs +Remaining arguments are added here. +#> + +[CmdletBinding()] +Param( + [string]$Target = "Default", + [ValidateSet("Release", "Debug")] + [string]$Configuration = "Release", + [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] + [string]$Verbosity = "Verbose", + [switch]$WhatIf, + [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] + [string[]]$ScriptArgs +) + +$FakeVersion = "4.61.2" +$NBenchVersion = "1.0.1" +$DotNetChannel = "preview"; +$DotNetVersion = "1.0.4"; +$DotNetInstallerUri = "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.ps1"; +$NugetVersion = "4.1.0"; +$NugetUrl = "https://dist.nuget.org/win-x86-commandline/v$NugetVersion/nuget.exe" +$ProtobufVersion = "3.2.0" +$DocfxVersion = "2.21.1" + +# Make sure tools folder exists +$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent +$ToolPath = Join-Path $PSScriptRoot "tools" +if (!(Test-Path $ToolPath)) { + Write-Verbose "Creating tools directory..." + New-Item -Path $ToolPath -Type directory | out-null +} + +########################################################################### +# INSTALL .NET CORE CLI +########################################################################### + +Function Remove-PathVariable([string]$VariableToRemove) +{ + $path = [Environment]::GetEnvironmentVariable("PATH", "User") + if ($path -ne $null) + { + $newItems = $path.Split(';', [StringSplitOptions]::RemoveEmptyEntries) | Where-Object { "$($_)" -inotlike $VariableToRemove } + [Environment]::SetEnvironmentVariable("PATH", [System.String]::Join(';', $newItems), "User") + } + + $path = [Environment]::GetEnvironmentVariable("PATH", "Process") + if ($path -ne $null) + { + $newItems = $path.Split(';', [StringSplitOptions]::RemoveEmptyEntries) | Where-Object { "$($_)" -inotlike $VariableToRemove } + [Environment]::SetEnvironmentVariable("PATH", [System.String]::Join(';', $newItems), "Process") + } +} + +# Get .NET Core CLI path if installed. +$FoundDotNetCliVersion = $null; +if (Get-Command dotnet -ErrorAction SilentlyContinue) { + $FoundDotNetCliVersion = dotnet --version; + $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + $env:DOTNET_CLI_TELEMETRY_OPTOUT=1 +} + +if($FoundDotNetCliVersion -ne $DotNetVersion) { + $InstallPath = Join-Path $PSScriptRoot ".dotnet" + if (!(Test-Path $InstallPath)) { + mkdir -Force $InstallPath | Out-Null; + } + (New-Object System.Net.WebClient).DownloadFile($DotNetInstallerUri, "$InstallPath\dotnet-install.ps1"); + & $InstallPath\dotnet-install.ps1 -Channel $DotNetChannel -Version $DotNetVersion -InstallDir $InstallPath -Architecture x64; + + Remove-PathVariable "$InstallPath" + $env:PATH = "$InstallPath;$env:PATH" + $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 + $env:DOTNET_CLI_TELEMETRY_OPTOUT=1 +} + +########################################################################### +# INSTALL NUGET +########################################################################### + +# Make sure nuget.exe exists. +$NugetPath = Join-Path $ToolPath "nuget.exe" +if (!(Test-Path $NugetPath)) { + Write-Host "Downloading NuGet.exe..." + (New-Object System.Net.WebClient).DownloadFile($NugetUrl, $NugetPath); +} + +########################################################################### +# INSTALL FAKE +########################################################################### +# Make sure Fake has been installed. + +$FakeExePath = Join-Path $ToolPath "FAKE/tools/FAKE.exe" +if (!(Test-Path $FakeExePath)) { + Write-Host "Installing Fake..." + Invoke-Expression "&`"$NugetPath`" install Fake -ExcludeVersion -Version $FakeVersion -OutputDirectory `"$ToolPath`"" | Out-Null; + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring Fake from NuGet." + } +} + +########################################################################### +# INSTALL NBench Runner +########################################################################### + +# Make sure NBench Runner has been installed. +$NBenchDllPath = Join-Path $ToolPath "NBench.Runner/lib/net45/NBench.Runner.exe" +if (!(Test-Path $NBenchDllPath)) { + Write-Host "Installing NBench..." + Invoke-Expression "&`"$NugetPath`" install NBench.Runner -ExcludeVersion -Version $NBenchVersion -OutputDirectory `"$ToolPath`"" | Out-Null; + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring NBench.Runner from NuGet." + } +} + +########################################################################### +# Google.Protobuf.Tools +########################################################################### + +# Make sure Google.Protobuf.Tools has been installed. +$ProtobufExePath = Join-Path $ToolPath "Google.Protobuf.Tools/tools/windows_x64/protoc.exe" +if (!(Test-Path $ProtobufExePath)) { + Write-Host "Installing Google.Protobuf.Tools..." + Invoke-Expression "&`"$NugetPath`" install Google.Protobuf.Tools -ExcludeVersion -Version $ProtobufVersion -OutputDirectory `"$ToolPath`"" | Out-Null; + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring Google.Protobuf.Tools from NuGet." + } +} + +########################################################################### +# Docfx +########################################################################### + +# Make sure Docfx has been installed. +$DocfxExePath = Join-Path $ToolPath "docfx.console/tools/docfx.exe" +if (!(Test-Path $DocfxExePath)) { + Write-Host "Installing Docfx..." + Invoke-Expression "&`"$NugetPath`" install docfx.console -ExcludeVersion -Version $DocfxVersion -OutputDirectory `"$ToolPath`"" | Out-Null; + if ($LASTEXITCODE -ne 0) { + Throw "An error occured while restoring docfx.console from NuGet." + } +} + +########################################################################### +# RUN BUILD SCRIPT +########################################################################### + +# Build the argument list. +$Arguments = @{ + target=$Target; + configuration=$Configuration; + verbosity=$Verbosity; + dryrun=$WhatIf; +}.GetEnumerator() | %{"--{0}=`"{1}`"" -f $_.key, $_.value }; + +# Start Fake +Write-Host "Running build script..." +Invoke-Expression "$FakeExePath `"build.fsx`" $ScriptArgs $Arguments" + +exit $LASTEXITCODE \ No newline at end of file diff --git a/build.sh b/build.sh index 99a99a75ea6..38a724a9904 100755 --- a/build.sh +++ b/build.sh @@ -1,40 +1,99 @@ -#!/bin/bash -SCRIPT_PATH="${BASH_SOURCE[0]}"; -if ([ -h "${SCRIPT_PATH}" ]) then - while([ -h "${SCRIPT_PATH}" ]) do SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done -fi -pushd . > /dev/null -cd `dirname ${SCRIPT_PATH}` > /dev/null -SCRIPT_PATH=`pwd`; -popd > /dev/null - -if ! [ -f $SCRIPT_PATH/src/.nuget/nuget.exe ] - then - wget "https://dist.nuget.org/win-x86-commandline/v4.1.0/nuget.exe" -P $SCRIPT_PATH/src/.nuget/ +#!/usr/bin/env bash +########################################################################## +# This is the Fake bootstrapper script for Linux and OS X. +########################################################################## + +# Define directories. +SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) +TOOLS_DIR=$SCRIPT_DIR/tools +NUGET_EXE=$TOOLS_DIR/nuget.exe +NUGET_URL=https://dist.nuget.org/win-x86-commandline/v4.0.0/nuget.exe +FAKE_VERSION=4.61.2 +FAKE_EXE=$TOOLS_DIR/FAKE/tools/FAKE.exe +DOTNET_VERSION=1.0.4 +DOTNET_INSTALLER_URL=https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.sh + +# Define default arguments. +TARGET="Default" +CONFIGURATION="Release" +VERBOSITY="verbose" +DRYRUN= +SCRIPT_ARGUMENTS=() + +# Parse arguments. +for i in "$@"; do + case $1 in + -t|--target) TARGET="$2"; shift ;; + -c|--configuration) CONFIGURATION="$2"; shift ;; + -v|--verbosity) VERBOSITY="$2"; shift ;; + -d|--dryrun) DRYRUN="-dryrun" ;; + --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;; + *) SCRIPT_ARGUMENTS+=("$1") ;; + esac + shift +done + +# Make sure the tools folder exist. +if [ ! -d "$TOOLS_DIR" ]; then + mkdir "$TOOLS_DIR" fi -SCRIPT_PATH="${BASH_SOURCE[0]}"; -if ([ -h "${SCRIPT_PATH}" ]) then - while([ -h "${SCRIPT_PATH}" ]) do SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done +########################################################################### +# INSTALL .NET CORE CLI +########################################################################### + +echo "Installing .NET CLI..." +if [ ! -d "$SCRIPT_DIR/.dotnet" ]; then + mkdir "$SCRIPT_DIR/.dotnet" fi -pushd . > /dev/null -cd `dirname ${SCRIPT_PATH}` > /dev/null -SCRIPT_PATH=`pwd`; -popd > /dev/null +curl -Lsfo "$SCRIPT_DIR/.dotnet/dotnet-install.sh" $DOTNET_INSTALLER_URL +bash "$SCRIPT_DIR/.dotnet/dotnet-install.sh" --version $DOTNET_VERSION --install-dir .dotnet --no-path +export PATH="$SCRIPT_DIR/.dotnet":$PATH +export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 +export DOTNET_CLI_TELEMETRY_OPTOUT=1 +chmod -R 0755 ".dotnet" +"$SCRIPT_DIR/.dotnet/dotnet" --info -mono $SCRIPT_PATH/src/.nuget/nuget.exe install FAKE -OutputDirectory $SCRIPT_PATH/src/packages -ExcludeVersion -Version 4.61.3 +########################################################################### +# INSTALL NUGET +########################################################################### -mono $SCRIPT_PATH/src/.nuget/nuget.exe install xunit.runner.console -OutputDirectory $SCRIPT_PATH/src/packages/FAKE -ExcludeVersion -Version 2.0.0 -mono $SCRIPT_PATH/src/.nuget/nuget.exe install NUnit.Console -OutputDirectory $SCRIPT_PATH/src/packages/FAKE -ExcludeVersion -Version 3.2.1 +# Download NuGet if it does not exist. +if [ ! -f "$NUGET_EXE" ]; then + echo "Downloading NuGet..." + curl -Lsfo "$NUGET_EXE" $NUGET_URL + if [ $? -ne 0 ]; then + echo "An error occured while downloading nuget.exe." + exit 1 + fi +fi -mono $SCRIPT_PATH/src/.nuget/nuget.exe install NBench.Runner -OutputDirectory $SCRIPT_PATH/src/packages -ExcludeVersion -Version 0.3.3 - +########################################################################### +# INSTALL FAKE +########################################################################### -if ! [ -e $SCRIPT_PATH/src/packages/SourceLink.Fake/tools/SourceLink.fsx ] ; then - mono $SCRIPT_PATH/src/.nuget/nuget.exe install SourceLink.Fake -OutputDirectory $SCRIPT_PATH/src/packages -ExcludeVersion +if [ ! -f "$FAKE_EXE" ]; then + mono "$NUGET_EXE" install Fake -ExcludeVersion -Version $FAKE_VERSION -OutputDirectory "$TOOLS_DIR" + if [ $? -ne 0 ]; then + echo "An error occured while installing Cake." + exit 1 + fi +fi +# Make sure that Fake has been installed. +if [ ! -f "$FAKE_EXE" ]; then + echo "Could not find Fake.exe at '$FAKE_EXE'." + exit 1 fi -export encoding=utf-8 +########################################################################### +# WORKAROUND FOR MONO +########################################################################### +export FrameworkPathOverride=/usr/lib/mono/4.5/ + +########################################################################### +# RUN BUILD SCRIPT +########################################################################### -mono $SCRIPT_PATH/src/packages/FAKE/tools/FAKE.exe build.fsx "$@" +# Start Fake +exec mono "$FAKE_EXE" build.fsx "${SCRIPT_ARGUMENTS[@]}" --verbosity=$VERBOSITY --configuration=$CONFIGURATION --target=$TARGET $DRYRUN diff --git a/buildIncremental.fsx b/buildIncremental.fsx new file mode 100644 index 00000000000..3033743dd92 --- /dev/null +++ b/buildIncremental.fsx @@ -0,0 +1,253 @@ +#I @"tools/FAKE/tools" +#r "FakeLib.dll" + +open System +open System.IO + +open Fake +open Fake.Git + +module IncrementalTests = + + let akkaDefaultBranch = "dev" + + type Supports = + | Windows + | Linux + | All + + let (|IsRunnable|_|) name platform (csproj:string) = + let isSupported = + match platform with + | Windows _ -> isWindows + | Linux _ -> isLinux + | All _ -> true + if (csproj.Contains(name) && isSupported) then Some(name) + else None + + let IsRunnable testProject = + match testProject with + | IsRunnable "Akka.API.Tests.csproj" Linux proj -> false + | _ -> true + + let getUnitTestProjects() = + let allTestProjects = !! "./**/core/**/*.Tests.csproj" + ++ "./**/contrib/**/*.Tests.csproj" + -- "./**/serializers/**/*Wire*.csproj" + allTestProjects + |> Seq.filter IsRunnable + + let isBuildScript (file:string) = + match file with + | EndsWith "fsx" -> true + | EndsWith "ps1" -> true + | EndsWith "cmd" -> true + | EndsWith "sh" -> true + | _ -> false + + let getHeadHashFor repositoryDir branch = + let _, msg, error = runGitCommand repositoryDir (sprintf "log --oneline -1 %s" branch) + if error <> "" then failwithf "git log --oneline failed: %s" error + let logMsg = msg |> Seq.head + let tmp = + logMsg.Split(' ') + |> Seq.head + |> fun s -> s.Split('m') + if tmp |> Array.length > 2 then tmp.[1].Substring(0,6) else tmp.[0].Substring(0,6) + + let getBranchesFileDiff repositoryDir branch = + let _, msg, error = runGitCommand repositoryDir (sprintf "diff %s --name-status" branch) + if error <> "" then failwithf "diff %s --name-status failed: %s" branch error + msg + |> Seq.map (fun line -> + let a = line.Split('\t') + FileStatus.Parse a.[0],a.[1]) + + let getUpstreamRemote repositoryDir = + let _, msg, error = runGitCommand repositoryDir "remote add upstream https://github.com/akkadotnet/akka.net" + match error with + | "" -> log "added upstream remote" + | "fatal: remote upstream already exists." -> log "upstream remote already exists" + | _ -> failwithf "remote add upstream https://github.com/akkadotnet/akka.net failed: %s" error + + let getUpdatedFiles() = + let srcDir = __SOURCE_DIRECTORY__ + log "Adding upstream remote..." + getUpstreamRemote srcDir + log "Fetching upstream remote to compare HEAD file changes with..." + directRunGitCommandAndFail srcDir "fetch upstream" + getBranchesFileDiff srcDir (sprintf "upstream/%s" akkaDefaultBranch) + |> Seq.map (fun (_, fi) -> FullName fi) + |> Seq.filter (fun fi -> (isInFolder (new DirectoryInfo("./src")) (new FileInfo(fi))) || (isBuildScript fi)) + + // Gather all of the folder paths that contain .csproj files + let getAllProjectFolders() = + !! "./src/**/*.csproj" + |> Seq.map (fun f -> DirectoryName (FullName f)) + + // Check if the altered file is inside of any of the folder paths that contain .csproj files + let isInProjectFolder projectFolder file = + isInFolder (new DirectoryInfo(projectFolder)) (new FileInfo(file)) + + type ProjectFileInclude = { projectFolder: string; file: string; contains: bool } + + // Return a collection of all projectFolder, altered file, and true/false is contained within + let generateContainingProjFileCollection alteredFiles = + getAllProjectFolders() + |> Seq.map (fun p -> alteredFiles |> Seq.map (fun f -> { projectFolder = p; file = f; contains = isInProjectFolder p f })) + |> Seq.concat + + // Find the .csproj file contained within a folder that contains an altered file + let findCsprojFilesForAlteredFiles fileProjectContainsSeq = + let findCsprojFileFor fileProjectContains = + //let projectFolder, file, contains = fileProjectContains + match fileProjectContains.contains with + | true -> Some(!! (fileProjectContains.projectFolder @@ "*.csproj") |> Seq.head) + | false -> None + fileProjectContainsSeq + |> Seq.map (fun x -> findCsprojFileFor x) + |> Seq.choose id + |> Seq.map (fun x -> filename x) + + let getAssemblyForProject project = + try + !! ("src" @@ "**" @@ "bin" @@ "Release" @@ "net452" @@ fileNameWithoutExt project + ".dll") + |> Seq.head + with + | :? System.ArgumentException as ex -> + logf "Could not find built assembly for %s. Make sure project is built in Release config." (fileNameWithoutExt project); + reraise() + + let getNetCoreAssemblyForProject project = + try + !! ("src" @@ "**" @@ "bin" @@ "Release" @@ "netcoreapp1.1" @@ fileNameWithoutExt project + ".dll") + |> Seq.head + with + | :? System.ArgumentException as ex -> + logfn "Could not find built assembly for %s. Make sure project is built in Release config." (fileNameWithoutExt project); + null + + //-------------------------------------------------------------------------------- + // MultiNodeTestRunner incremental test selection + //-------------------------------------------------------------------------------- + + let getMntrProjects() = + !! "./src/**/*Tests.MultiNode.csproj" + |> Seq.map (fun x -> x.ToString()) + + let getAllMntrTestAssemblies() = // if we're not running incremental tests + getMntrProjects() + |> Seq.map (fun x -> getAssemblyForProject x) + + let getAllMntrTestNetCoreAssemblies() = // if we're not running incremental tests + getMntrProjects() + |> Seq.map (fun x -> getNetCoreAssemblyForProject x) + + //-------------------------------------------------------------------------------- + // Performance tests incremental test selection + //-------------------------------------------------------------------------------- + + let getPerfTestProjects() = + !! "./src/**/*Tests.Performance.csproj" + |> Seq.map (fun x -> x.ToString()) + + let getAllPerfTestAssemblies() = //if we're not running incremental tests + getPerfTestProjects() + |> Seq.map (fun x -> getAssemblyForProject x) + + //-------------------------------------------------------------------------------- + // Recursive dependency search + //-------------------------------------------------------------------------------- + + type ProjectPath = { projectName: string; projectPath: string } + type ProjectDetails = { parentProject: ProjectPath; dependencies: ProjectPath seq; isTestProject: bool } + + let FullNameLinux baseProj csprojRef = + let csprojRef = normalizePath csprojRef + let mutable workingDirPath = DirectoryName baseProj + let csprojRefParts = split '/' csprojRef + let rootPath = + csprojRefParts + |> List.filter (fun x -> x = "..") + |> List.iter (fun x -> workingDirPath <- (DirectoryName workingDirPath)) + workingDirPath + let subPath = + csprojRefParts + |> List.filter (fun x -> not (x = "..")) + |> List.reduce (@@) + rootPath @@ subPath + + let getDependentProjectFilePath baseProj csprojRef = + match isWindows with + | true -> FullName csprojRef + | _ -> FullNameLinux baseProj csprojRef + + let getDependentProjects csprojFile = + XMLRead true csprojFile "" "" "//Project/ItemGroup/ProjectReference/@Include" + |> Seq.map (fun p -> { projectName = filename (normalizePath p); projectPath = getDependentProjectFilePath csprojFile p }) + + type TestMode = + | Unit + | MNTR + | Perf + + let isTestProject csproj testMode = + match testMode with + | Unit -> (filename csproj).Contains("Tests.csproj") + | MNTR -> (filename csproj).Contains("Tests.MultiNode.csproj") + | Perf -> (filename csproj).Contains("Tests.Performance.csproj") + + let getAllProjectDependencies testMode = + !! "./src/**/*.csproj" + |> Seq.map (fun f -> { parentProject = { projectName = filename f; projectPath = f }; dependencies = getDependentProjects f; isTestProject = isTestProject f testMode }) + + let rec findTestProjectsThatHaveDependencyOn project testMode = + let allProjects = getAllProjectDependencies testMode + seq { for proj in allProjects do + for dep in proj.dependencies do + if (proj.parentProject.projectName = project && proj.isTestProject) then + // if the altered project is a test project (e.g. Akka.Tests) + yield proj; + if (dep.projectName = project && proj.isTestProject) then + //logfn "%s references %s and is a test project..." proj.parentProject.projectName project + yield proj + elif (dep.projectName = project && not proj.isTestProject) then + //logfn "%s references %s but is not a test project..." proj.parentProject.projectName project + yield! findTestProjectsThatHaveDependencyOn proj.parentProject.projectName testMode } + + let getIncrementalTestProjects2 testMode = + logfn "Searching for incremental tests to run in %s test mode..." (testMode.ToString()) + let updatedFiles = getUpdatedFiles() + log "The following files have been updated since forking from dev branch..." + updatedFiles |> Seq.iter (fun x -> logfn "\t%s" x) + log "The following test projects will be run..." + if (updatedFiles |> Seq.exists (fun p -> isBuildScript p)) then + log "Full test suite" + match testMode with + | Unit -> getUnitTestProjects() + | MNTR -> getMntrProjects() + | Perf -> getPerfTestProjects() + else + updatedFiles + |> generateContainingProjFileCollection + |> findCsprojFilesForAlteredFiles + |> Seq.map (fun p -> findTestProjectsThatHaveDependencyOn p testMode) + |> Seq.concat + |> Seq.map (fun p -> p.parentProject.projectPath) + |> Seq.distinct + |> Seq.filter IsRunnable + + let getIncrementalUnitTests() = + getIncrementalTestProjects2 Unit + + let getIncrementalMNTRTests() = + getIncrementalTestProjects2 MNTR + |> Seq.map (fun p -> getAssemblyForProject p) + + let getIncrementalNetCoreMNTRTests() = + getIncrementalTestProjects2 MNTR + |> Seq.map (fun p -> getNetCoreAssemblyForProject p) + + let getIncrementalPerfTests() = + getIncrementalTestProjects2 Perf + |> Seq.map (fun p -> getAssemblyForProject p) diff --git a/docs/api/.gitignore b/docs/api/.gitignore index da7c71b83ab..7e7bb375b86 100644 --- a/docs/api/.gitignore +++ b/docs/api/.gitignore @@ -2,3 +2,4 @@ # temp file # ############### *.yml +.manifest \ No newline at end of file diff --git a/docs/api/.manifest b/docs/api/.manifest deleted file mode 100644 index 7f86615d02f..00000000000 --- a/docs/api/.manifest +++ /dev/null @@ -1 +0,0 @@ -{"Akka":"Akka.yml","Akka.NotUsed":"Akka.NotUsed.yml","Akka.NotUsed.Instance":"Akka.NotUsed.yml","Akka.NotUsed.GetHashCode":"Akka.NotUsed.yml","Akka.NotUsed.Equals(System.Object)":"Akka.NotUsed.yml","Akka.NotUsed.ToString":"Akka.NotUsed.yml","Akka.NotUsed.Equals(Akka.NotUsed)":"Akka.NotUsed.yml","Akka.NotUsed.CompareTo(Akka.NotUsed)":"Akka.NotUsed.yml","Akka.PatternMatch":"Akka.PatternMatch.yml","Akka.PatternMatch.Match(System.Object)":"Akka.PatternMatch.yml","Akka.PatternMatch.Match``1(System.Object)":"Akka.PatternMatch.yml","Akka.IMatchResult":"Akka.IMatchResult.yml","Akka.IMatchResult.WasHandled":"Akka.IMatchResult.yml","Akka.Case":"Akka.Case.yml","Akka.Case.WasHandled":"Akka.Case.yml","Akka.Case.#ctor(System.Object)":"Akka.Case.yml","Akka.Case.With``1(System.Action)":"Akka.Case.yml","Akka.Case.With``1(System.Action{``0})":"Akka.Case.yml","Akka.Case.Default(System.Action{System.Object})":"Akka.Case.yml","Akka.Case`1":"Akka.Case-1.yml","Akka.Case`1.WasHandled":"Akka.Case-1.yml","Akka.Case`1.#ctor(System.Object)":"Akka.Case-1.yml","Akka.Case`1.With``1(System.Func{`0})":"Akka.Case-1.yml","Akka.Case`1.With``1(System.Func{``0,`0})":"Akka.Case-1.yml","Akka.Case`1.ResultOrDefault(System.Func{System.Object,`0})":"Akka.Case-1.yml","Akka.Actor":"Akka.Actor.yml","Akka.Actor.ActorCell":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Watch(Akka.Actor.IActorRef)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Unwatch(Akka.Actor.IActorRef)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.ReceivedTerminated(Akka.Actor.Terminated)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.WatchedActorTerminated(Akka.Actor.IActorRef,System.Boolean,System.Boolean)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.TerminatedQueuedFor(Akka.Actor.IActorRef)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.TellWatchersWeDied":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.UnwatchWatchedActors(Akka.Actor.ActorBase)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.AddWatcher(Akka.Actor.IActorRef,Akka.Actor.IActorRef)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.RemWatcher(Akka.Actor.IActorRef,Akka.Actor.IActorRef)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.AddressTerminated(Akka.Actor.Address)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.UndefinedUid":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Stash(Akka.Dispatch.SysMsg.SystemMessage)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.#ctor(Akka.Actor.Internal.ActorSystemImpl,Akka.Actor.IInternalActorRef,Akka.Actor.Props,Akka.Dispatch.MessageDispatcher,Akka.Actor.IInternalActorRef)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.CurrentMessage":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Mailbox":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Dispatcher":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.IsLocal":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Actor":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.IsTerminated":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.System":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.SystemImpl":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Props":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Self":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Akka#Actor#IActorContext#Parent":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Parent":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Sender":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.HasMessages":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.NumberOfMessages":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.TaskScheduler":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Init(System.Boolean,Akka.Dispatch.MailboxType)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.GetChildByName(System.String)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Akka#Actor#IActorContext#Child(System.String)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.ActorSelection(System.String)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.ActorSelection(Akka.Actor.ActorPath)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Akka#Actor#IActorContext#GetChildren":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.GetChildren":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Become(Akka.Actor.Receive)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.BecomeStacked(Akka.Actor.Receive)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Akka#Actor#IActorContext#Become(Akka.Actor.Receive,System.Boolean)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Akka#Actor#IActorContext#Unbecome":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.UnbecomeStacked":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Akka#Actor#IUntypedActorContext#Become(Akka.Actor.UntypedReceive)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Akka#Actor#IUntypedActorContext#BecomeStacked(Akka.Actor.UntypedReceive)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Akka#Actor#IUntypedActorContext#Become(Akka.Actor.UntypedReceive,System.Boolean)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.CreateNewActorInstance":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.UseThreadContext(System.Action)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.SendMessage(Akka.Actor.Envelope)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.SendMessage(Akka.Actor.IActorRef,System.Object)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.ClearActorCell":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.ClearActor(Akka.Actor.ActorBase)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.PrepareForNewActor":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.SetActorFields(Akka.Actor.ActorBase)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.SplitNameAndUid(System.String)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.GetCurrentSelfOrNoSender":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.GetCurrentSenderOrNoSender":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.CurrentEnvelopeId":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Invoke(Akka.Actor.Envelope)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.AutoReceiveMessage(Akka.Actor.Envelope)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.ReceiveMessageForTest(Akka.Actor.Envelope)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Restart(System.Exception)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Start":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.PreStart":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Resume(System.Exception)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Stop":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Suspend":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.SetReceiveTimeout(System.Nullable{System.TimeSpan})":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.ReceiveTimeout":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.CheckReceiveTimeout":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.ChildrenContainer":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.AttachChild(Akka.Actor.Props,System.Boolean,System.String)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.ActorOf(Akka.Actor.Props,System.String)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.Stop(Akka.Actor.IActorRef)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.ReserveChild(System.String)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.UnreserveChild(System.String)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.InitChild(Akka.Actor.IInternalActorRef)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.SetChildrenTerminationReason(Akka.Actor.Internal.SuspendReason)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.SetTerminated":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.IsNormal":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.IsTerminating":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.TryGetChildStatsByName(System.String,Akka.Actor.Internal.IChildStats@)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.TryGetChildStatsByRef(Akka.Actor.IActorRef,Akka.Actor.Internal.ChildRestartStats@)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.GetSingleChild(System.String)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.TryGetSingleChild(System.String,Akka.Actor.IInternalActorRef@)":"Akka.Actor.ActorCell.yml","Akka.Actor.ActorCell.RemoveChildAndGetStateChange(Akka.Actor.IActorRef)":"Akka.Actor.ActorCell.yml","Akka.Actor.IActorProducerPlugin":"Akka.Actor.IActorProducerPlugin.yml","Akka.Actor.IActorProducerPlugin.CanBeAppliedTo(System.Type)":"Akka.Actor.IActorProducerPlugin.yml","Akka.Actor.IActorProducerPlugin.AfterIncarnated(Akka.Actor.ActorBase,Akka.Actor.IActorContext)":"Akka.Actor.IActorProducerPlugin.yml","Akka.Actor.IActorProducerPlugin.BeforeIncarnated(Akka.Actor.ActorBase,Akka.Actor.IActorContext)":"Akka.Actor.IActorProducerPlugin.yml","Akka.Actor.ActorProducerPluginBase":"Akka.Actor.ActorProducerPluginBase.yml","Akka.Actor.ActorProducerPluginBase.CanBeAppliedTo(System.Type)":"Akka.Actor.ActorProducerPluginBase.yml","Akka.Actor.ActorProducerPluginBase.AfterIncarnated(Akka.Actor.ActorBase,Akka.Actor.IActorContext)":"Akka.Actor.ActorProducerPluginBase.yml","Akka.Actor.ActorProducerPluginBase.BeforeIncarnated(Akka.Actor.ActorBase,Akka.Actor.IActorContext)":"Akka.Actor.ActorProducerPluginBase.yml","Akka.Actor.ActorProducerPluginBase`1":"Akka.Actor.ActorProducerPluginBase-1.yml","Akka.Actor.ActorProducerPluginBase`1.CanBeAppliedTo(System.Type)":"Akka.Actor.ActorProducerPluginBase-1.yml","Akka.Actor.ActorProducerPluginBase`1.Akka#Actor#IActorProducerPlugin#AfterIncarnated(Akka.Actor.ActorBase,Akka.Actor.IActorContext)":"Akka.Actor.ActorProducerPluginBase-1.yml","Akka.Actor.ActorProducerPluginBase`1.Akka#Actor#IActorProducerPlugin#BeforeIncarnated(Akka.Actor.ActorBase,Akka.Actor.IActorContext)":"Akka.Actor.ActorProducerPluginBase-1.yml","Akka.Actor.ActorProducerPluginBase`1.AfterIncarnated(`0,Akka.Actor.IActorContext)":"Akka.Actor.ActorProducerPluginBase-1.yml","Akka.Actor.ActorProducerPluginBase`1.BeforeIncarnated(`0,Akka.Actor.IActorContext)":"Akka.Actor.ActorProducerPluginBase-1.yml","Akka.Actor.ActorProducerPipelineResolver":"Akka.Actor.ActorProducerPipelineResolver.yml","Akka.Actor.ActorProducerPipelineResolver.TotalPluginCount":"Akka.Actor.ActorProducerPipelineResolver.yml","Akka.Actor.ActorProducerPipelineResolver.#ctor(System.Func{Akka.Event.ILoggingAdapter})":"Akka.Actor.ActorProducerPipelineResolver.yml","Akka.Actor.ActorProducerPipelineResolver.Register(Akka.Actor.IActorProducerPlugin)":"Akka.Actor.ActorProducerPipelineResolver.yml","Akka.Actor.ActorProducerPipelineResolver.Insert(System.Int32,Akka.Actor.IActorProducerPlugin)":"Akka.Actor.ActorProducerPipelineResolver.yml","Akka.Actor.ActorProducerPipelineResolver.Unregister(Akka.Actor.IActorProducerPlugin)":"Akka.Actor.ActorProducerPipelineResolver.yml","Akka.Actor.ActorProducerPipelineResolver.IsRegistered(Akka.Actor.IActorProducerPlugin)":"Akka.Actor.ActorProducerPipelineResolver.yml","Akka.Actor.ActorProducerPipeline":"Akka.Actor.ActorProducerPipeline.yml","Akka.Actor.ActorProducerPipeline.#ctor(System.Lazy{Akka.Event.ILoggingAdapter},System.Collections.Generic.IEnumerable{Akka.Actor.IActorProducerPlugin})":"Akka.Actor.ActorProducerPipeline.yml","Akka.Actor.ActorProducerPipeline.Count":"Akka.Actor.ActorProducerPipeline.yml","Akka.Actor.ActorProducerPipeline.AfterActorIncarnated(Akka.Actor.ActorBase,Akka.Actor.IActorContext)":"Akka.Actor.ActorProducerPipeline.yml","Akka.Actor.ActorProducerPipeline.BeforeActorIncarnated(Akka.Actor.ActorBase,Akka.Actor.IActorContext)":"Akka.Actor.ActorProducerPipeline.yml","Akka.Actor.ActorProducerPipeline.GetEnumerator":"Akka.Actor.ActorProducerPipeline.yml","Akka.Actor.ActorProducerPipeline.System#Collections#IEnumerable#GetEnumerator":"Akka.Actor.ActorProducerPipeline.yml","Akka.Actor.AlreadyCanceledCancelable":"Akka.Actor.AlreadyCanceledCancelable.yml","Akka.Actor.AlreadyCanceledCancelable.Cancel":"Akka.Actor.AlreadyCanceledCancelable.yml","Akka.Actor.AlreadyCanceledCancelable.IsCancellationRequested":"Akka.Actor.AlreadyCanceledCancelable.yml","Akka.Actor.AlreadyCanceledCancelable.Instance":"Akka.Actor.AlreadyCanceledCancelable.yml","Akka.Actor.AlreadyCanceledCancelable.Token":"Akka.Actor.AlreadyCanceledCancelable.yml","Akka.Actor.AlreadyCanceledCancelable.Akka#Actor#ICancelable#CancelAfter(System.TimeSpan)":"Akka.Actor.AlreadyCanceledCancelable.yml","Akka.Actor.AlreadyCanceledCancelable.Akka#Actor#ICancelable#CancelAfter(System.Int32)":"Akka.Actor.AlreadyCanceledCancelable.yml","Akka.Actor.AlreadyCanceledCancelable.Cancel(System.Boolean)":"Akka.Actor.AlreadyCanceledCancelable.yml","Akka.Actor.CancelableExtensions":"Akka.Actor.CancelableExtensions.yml","Akka.Actor.CancelableExtensions.CancelIfNotNull(Akka.Actor.ICancelable)":"Akka.Actor.CancelableExtensions.yml","Akka.Actor.Cancelable":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.#ctor(Akka.Actor.IActionScheduler,System.TimeSpan)":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.#ctor(Akka.Actor.IScheduler,System.TimeSpan)":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.#ctor(Akka.Actor.IScheduler,System.Int32)":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.#ctor(Akka.Actor.IScheduler)":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.#ctor(Akka.Actor.IActionScheduler)":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.IsCancellationRequested":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.Token":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.Cancel":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.Cancel(System.Boolean)":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.CancelAfter(System.TimeSpan)":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.CancelAfter(System.Int32)":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.CreateCanceled":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.CreateLinkedCancelable(Akka.Actor.IScheduler,Akka.Actor.ICancelable[])":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.CreateLinkedCancelable(Akka.Actor.IActionScheduler,Akka.Actor.ICancelable[])":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.Dispose":"Akka.Actor.Cancelable.yml","Akka.Actor.Cancelable.Dispose(System.Boolean)":"Akka.Actor.Cancelable.yml","Akka.Actor.ICancelable":"Akka.Actor.ICancelable.yml","Akka.Actor.ICancelable.Cancel":"Akka.Actor.ICancelable.yml","Akka.Actor.ICancelable.IsCancellationRequested":"Akka.Actor.ICancelable.yml","Akka.Actor.ICancelable.Token":"Akka.Actor.ICancelable.yml","Akka.Actor.ICancelable.CancelAfter(System.TimeSpan)":"Akka.Actor.ICancelable.yml","Akka.Actor.ICancelable.CancelAfter(System.Int32)":"Akka.Actor.ICancelable.yml","Akka.Actor.ICancelable.Cancel(System.Boolean)":"Akka.Actor.ICancelable.yml","Akka.Actor.DateTimeOffsetNowTimeProvider":"Akka.Actor.DateTimeOffsetNowTimeProvider.yml","Akka.Actor.DateTimeOffsetNowTimeProvider.Now":"Akka.Actor.DateTimeOffsetNowTimeProvider.yml","Akka.Actor.DateTimeOffsetNowTimeProvider.MonotonicClock":"Akka.Actor.DateTimeOffsetNowTimeProvider.yml","Akka.Actor.DateTimeOffsetNowTimeProvider.HighResMonotonicClock":"Akka.Actor.DateTimeOffsetNowTimeProvider.yml","Akka.Actor.DateTimeOffsetNowTimeProvider.Instance":"Akka.Actor.DateTimeOffsetNowTimeProvider.yml","Akka.Actor.DedicatedThreadScheduler":"Akka.Actor.DedicatedThreadScheduler.yml","Akka.Actor.DedicatedThreadScheduler.TimeNow":"Akka.Actor.DedicatedThreadScheduler.yml","Akka.Actor.DedicatedThreadScheduler.MonotonicClock":"Akka.Actor.DedicatedThreadScheduler.yml","Akka.Actor.DedicatedThreadScheduler.HighResMonotonicClock":"Akka.Actor.DedicatedThreadScheduler.yml","Akka.Actor.DedicatedThreadScheduler.#ctor(Akka.Actor.ActorSystem)":"Akka.Actor.DedicatedThreadScheduler.yml","Akka.Actor.DedicatedThreadScheduler.#ctor(Akka.Configuration.Config,Akka.Event.ILoggingAdapter)":"Akka.Actor.DedicatedThreadScheduler.yml","Akka.Actor.DedicatedThreadScheduler.InternalScheduleTellOnce(System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef,Akka.Actor.ICancelable)":"Akka.Actor.DedicatedThreadScheduler.yml","Akka.Actor.DedicatedThreadScheduler.InternalScheduleTellRepeatedly(System.TimeSpan,System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef,Akka.Actor.ICancelable)":"Akka.Actor.DedicatedThreadScheduler.yml","Akka.Actor.DedicatedThreadScheduler.InternalScheduleOnce(System.TimeSpan,System.Action,Akka.Actor.ICancelable)":"Akka.Actor.DedicatedThreadScheduler.yml","Akka.Actor.DedicatedThreadScheduler.InternalScheduleRepeatedly(System.TimeSpan,System.TimeSpan,System.Action,Akka.Actor.ICancelable)":"Akka.Actor.DedicatedThreadScheduler.yml","Akka.Actor.DedicatedThreadScheduler.Dispose":"Akka.Actor.DedicatedThreadScheduler.yml","Akka.Actor.ScheduledWork":"Akka.Actor.ScheduledWork.yml","Akka.Actor.ScheduledWork.#ctor(System.Int64,System.Action,System.Threading.CancellationToken)":"Akka.Actor.ScheduledWork.yml","Akka.Actor.ScheduledWork.Token":"Akka.Actor.ScheduledWork.yml","Akka.Actor.ScheduledWork.TickExpires":"Akka.Actor.ScheduledWork.yml","Akka.Actor.ScheduledWork.Action":"Akka.Actor.ScheduledWork.yml","Akka.Actor.IDateTimeOffsetNowTimeProvider":"Akka.Actor.IDateTimeOffsetNowTimeProvider.yml","Akka.Actor.ITimeProvider":"Akka.Actor.ITimeProvider.yml","Akka.Actor.ITimeProvider.Now":"Akka.Actor.ITimeProvider.yml","Akka.Actor.ITimeProvider.MonotonicClock":"Akka.Actor.ITimeProvider.yml","Akka.Actor.ITimeProvider.HighResMonotonicClock":"Akka.Actor.ITimeProvider.yml","Akka.Actor.DeprecatedSchedulerExtensions":"Akka.Actor.DeprecatedSchedulerExtensions.yml","Akka.Actor.DeprecatedSchedulerExtensions.ScheduleOnce(Akka.Actor.IScheduler,System.TimeSpan,Akka.Actor.IActorRef,System.Object)":"Akka.Actor.DeprecatedSchedulerExtensions.yml","Akka.Actor.DeprecatedSchedulerExtensions.ScheduleOnce(Akka.Actor.IScheduler,System.TimeSpan,Akka.Actor.IActorRef,System.Object,System.Threading.CancellationToken)":"Akka.Actor.DeprecatedSchedulerExtensions.yml","Akka.Actor.DeprecatedSchedulerExtensions.Schedule(Akka.Actor.IScheduler,System.TimeSpan,System.TimeSpan,Akka.Actor.IActorRef,System.Object)":"Akka.Actor.DeprecatedSchedulerExtensions.yml","Akka.Actor.DeprecatedSchedulerExtensions.Schedule(Akka.Actor.IScheduler,System.TimeSpan,System.TimeSpan,Akka.Actor.IActorRef,System.Object,System.Threading.CancellationToken)":"Akka.Actor.DeprecatedSchedulerExtensions.yml","Akka.Actor.DeprecatedSchedulerExtensions.Schedule(Akka.Actor.IScheduler,System.TimeSpan,System.TimeSpan,System.Action)":"Akka.Actor.DeprecatedSchedulerExtensions.yml","Akka.Actor.DeprecatedSchedulerExtensions.Schedule(Akka.Actor.IScheduler,System.TimeSpan,System.TimeSpan,System.Action,System.Threading.CancellationToken)":"Akka.Actor.DeprecatedSchedulerExtensions.yml","Akka.Actor.DeprecatedSchedulerExtensions.ScheduleOnce(Akka.Actor.IScheduler,System.TimeSpan,System.Action)":"Akka.Actor.DeprecatedSchedulerExtensions.yml","Akka.Actor.DeprecatedSchedulerExtensions.ScheduleOnce(Akka.Actor.IScheduler,System.TimeSpan,System.Action,System.Threading.CancellationToken)":"Akka.Actor.DeprecatedSchedulerExtensions.yml","Akka.Actor.IActionScheduler":"Akka.Actor.IActionScheduler.yml","Akka.Actor.IActionScheduler.ScheduleOnce(System.TimeSpan,System.Action,Akka.Actor.ICancelable)":"Akka.Actor.IActionScheduler.yml","Akka.Actor.IActionScheduler.ScheduleOnce(System.TimeSpan,System.Action)":"Akka.Actor.IActionScheduler.yml","Akka.Actor.IActionScheduler.ScheduleRepeatedly(System.TimeSpan,System.TimeSpan,System.Action,Akka.Actor.ICancelable)":"Akka.Actor.IActionScheduler.yml","Akka.Actor.IActionScheduler.ScheduleRepeatedly(System.TimeSpan,System.TimeSpan,System.Action)":"Akka.Actor.IActionScheduler.yml","Akka.Actor.IAdvancedScheduler":"Akka.Actor.IAdvancedScheduler.yml","Akka.Actor.IScheduler":"Akka.Actor.IScheduler.yml","Akka.Actor.IScheduler.Advanced":"Akka.Actor.IScheduler.yml","Akka.Actor.ReceiveActor":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.#ctor":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.Akka#Actor#Internal#IInitializableActor#Init":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.OnReceive(System.Object)":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.Become(System.Action)":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.BecomeStacked(System.Action)":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.Become(System.Action,System.Boolean)":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.Receive``1(System.Func{``0,System.Threading.Tasks.Task})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.ReceiveAsync``1(System.Func{``0,System.Threading.Tasks.Task},System.Predicate{``0})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.ReceiveAsync``1(System.Predicate{``0},System.Func{``0,System.Threading.Tasks.Task})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.ReceiveAsync(System.Type,System.Func{System.Object,System.Threading.Tasks.Task},System.Predicate{System.Object})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.ReceiveAsync(System.Type,System.Predicate{System.Object},System.Func{System.Object,System.Threading.Tasks.Task})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.ReceiveAnyAsync(System.Func{System.Object,System.Threading.Tasks.Task})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.Receive``1(System.Action{``0},System.Predicate{``0})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.Receive``1(System.Predicate{``0},System.Action{``0})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.Receive(System.Type,System.Action{System.Object},System.Predicate{System.Object})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.Receive(System.Type,System.Predicate{System.Object},System.Action{System.Object})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.Receive``1(System.Func{``0,System.Boolean})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.Receive(System.Type,System.Func{System.Object,System.Boolean})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.ReceiveActor.ReceiveAny(System.Action{System.Object})":"Akka.Actor.ReceiveActor.yml","Akka.Actor.Status":"Akka.Actor.Status.yml","Akka.Actor.Status.Success":"Akka.Actor.Status.Success.yml","Akka.Actor.Status.Success.Status":"Akka.Actor.Status.Success.yml","Akka.Actor.Status.Success.#ctor(System.Object)":"Akka.Actor.Status.Success.yml","Akka.Actor.Status.Failure":"Akka.Actor.Status.Failure.yml","Akka.Actor.Status.Failure.Cause":"Akka.Actor.Status.Failure.yml","Akka.Actor.Status.Failure.#ctor(System.Exception)":"Akka.Actor.Status.Failure.yml","Akka.Actor.Status.Failure.ToString":"Akka.Actor.Status.Failure.yml","Akka.Actor.ILogReceive":"Akka.Actor.ILogReceive.yml","Akka.Actor.IActorLogging":"Akka.Actor.IActorLogging.yml","Akka.Actor.IActorLogging.Log":"Akka.Actor.IActorLogging.yml","Akka.Actor.IInternalActor":"Akka.Actor.IInternalActor.yml","Akka.Actor.IInternalActor.ActorContext":"Akka.Actor.IInternalActor.yml","Akka.Actor.ActorBase":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.#ctor":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.Sender":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.Self":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.Akka#Actor#IInternalActor#ActorContext":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.Context":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.AroundReceive(Akka.Actor.Receive,System.Object)":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.Receive(System.Object)":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.EmptyReceive":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.Unhandled(System.Object)":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.Become(Akka.Actor.Receive,System.Boolean)":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.Become(Akka.Actor.Receive)":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.BecomeStacked(Akka.Actor.Receive)":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.UnbecomeStacked":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.Unbecome":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.SetReceiveTimeout(System.Nullable{System.TimeSpan})":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.SupervisorStrategy":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.AroundPreRestart(System.Exception,System.Object)":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.AroundPreStart":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.PreStart":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.AroundPostRestart(System.Exception,System.Object)":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.PreRestart(System.Exception,System.Object)":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.PostRestart(System.Exception)":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.AroundPostStop":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorBase.PostStop":"Akka.Actor.ActorBase.yml","Akka.Actor.ActorPath":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.IsValidPathElement(System.String)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.#ctor(Akka.Actor.Address,System.String)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.#ctor(Akka.Actor.ActorPath,System.String,System.Int64)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.Uid":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.Elements":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.ElementsWithUid":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.Name":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.Address":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.Root":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.Parent":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.Equals(Akka.Actor.ActorPath)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.CompareTo(Akka.Actor.ActorPath)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.WithUid(System.Int64)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.op_Division(Akka.Actor.ActorPath,System.String)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.op_Division(Akka.Actor.ActorPath,System.Collections.Generic.IEnumerable{System.String})":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.Parse(System.String)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.TryParse(System.String,Akka.Actor.ActorPath@)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.TryParseAddress(System.String,Akka.Actor.Address@)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.ToStringWithoutAddress":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.ToString":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.ToStringWithUid":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.Child(System.String)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.GetHashCode":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.Equals(System.Object)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.op_Equality(Akka.Actor.ActorPath,Akka.Actor.ActorPath)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.op_Inequality(Akka.Actor.ActorPath,Akka.Actor.ActorPath)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.ToStringWithAddress":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.ToSerializationFormat":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.ToSerializationFormatWithAddress(Akka.Actor.Address)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.ToStringWithAddress(Akka.Actor.Address)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.FormatPathElements(System.Collections.Generic.IEnumerable{System.String})":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.ActorPath.yml","Akka.Actor.ActorPath.Surrogate":"Akka.Actor.ActorPath.Surrogate.yml","Akka.Actor.ActorPath.Surrogate.#ctor(System.String)":"Akka.Actor.ActorPath.Surrogate.yml","Akka.Actor.ActorPath.Surrogate.Path":"Akka.Actor.ActorPath.Surrogate.yml","Akka.Actor.ActorPath.Surrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.ActorPath.Surrogate.yml","Akka.Actor.ActorPath.Surrogate.Equals(Akka.Actor.ActorPath.Surrogate)":"Akka.Actor.ActorPath.Surrogate.yml","Akka.Actor.ActorPath.Surrogate.Equals(Akka.Actor.ActorPath)":"Akka.Actor.ActorPath.Surrogate.yml","Akka.Actor.ActorPath.Surrogate.Equals(System.Object)":"Akka.Actor.ActorPath.Surrogate.yml","Akka.Actor.ActorPath.Surrogate.GetHashCode":"Akka.Actor.ActorPath.Surrogate.yml","Akka.Actor.RootActorPath":"Akka.Actor.RootActorPath.yml","Akka.Actor.RootActorPath.#ctor(Akka.Actor.Address,System.String)":"Akka.Actor.RootActorPath.yml","Akka.Actor.RootActorPath.Parent":"Akka.Actor.RootActorPath.yml","Akka.Actor.RootActorPath.Root":"Akka.Actor.RootActorPath.yml","Akka.Actor.RootActorPath.WithUid(System.Int64)":"Akka.Actor.RootActorPath.yml","Akka.Actor.RootActorPath.CompareTo(Akka.Actor.ActorPath)":"Akka.Actor.RootActorPath.yml","Akka.Actor.ChildActorPath":"Akka.Actor.ChildActorPath.yml","Akka.Actor.ChildActorPath.#ctor(Akka.Actor.ActorPath,System.String,System.Int64)":"Akka.Actor.ChildActorPath.yml","Akka.Actor.ChildActorPath.Parent":"Akka.Actor.ChildActorPath.yml","Akka.Actor.ChildActorPath.Root":"Akka.Actor.ChildActorPath.yml","Akka.Actor.ChildActorPath.WithUid(System.Int64)":"Akka.Actor.ChildActorPath.yml","Akka.Actor.ChildActorPath.CompareTo(Akka.Actor.ActorPath)":"Akka.Actor.ChildActorPath.yml","Akka.Actor.IActorRefScope":"Akka.Actor.IActorRefScope.yml","Akka.Actor.IActorRefScope.IsLocal":"Akka.Actor.IActorRefScope.yml","Akka.Actor.IRepointableRef":"Akka.Actor.IRepointableRef.yml","Akka.Actor.IRepointableRef.IsStarted":"Akka.Actor.IRepointableRef.yml","Akka.Actor.FutureActorRef":"Akka.Actor.FutureActorRef.yml","Akka.Actor.FutureActorRef.#ctor(System.Threading.Tasks.TaskCompletionSource{System.Object},System.Action,Akka.Actor.ActorPath)":"Akka.Actor.FutureActorRef.yml","Akka.Actor.FutureActorRef.Path":"Akka.Actor.FutureActorRef.yml","Akka.Actor.FutureActorRef.Provider":"Akka.Actor.FutureActorRef.yml","Akka.Actor.FutureActorRef.TellInternal(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.FutureActorRef.yml","Akka.Actor.FutureActorRef.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage)":"Akka.Actor.FutureActorRef.yml","Akka.Actor.IActorRef":"Akka.Actor.IActorRef.yml","Akka.Actor.IActorRef.Path":"Akka.Actor.IActorRef.yml","Akka.Actor.ActorRefImplicitSenderExtensions":"Akka.Actor.ActorRefImplicitSenderExtensions.yml","Akka.Actor.ActorRefImplicitSenderExtensions.Tell(Akka.Actor.IActorRef,System.Object)":"Akka.Actor.ActorRefImplicitSenderExtensions.yml","Akka.Actor.ActorRefImplicitSenderExtensions.Forward(Akka.Actor.IActorRef,System.Object)":"Akka.Actor.ActorRefImplicitSenderExtensions.yml","Akka.Actor.ActorRefs":"Akka.Actor.ActorRefs.yml","Akka.Actor.ActorRefs.Nobody":"Akka.Actor.ActorRefs.yml","Akka.Actor.ActorRefs.NoSender":"Akka.Actor.ActorRefs.yml","Akka.Actor.ActorRefBase":"Akka.Actor.ActorRefBase.yml","Akka.Actor.ActorRefBase.Path":"Akka.Actor.ActorRefBase.yml","Akka.Actor.ActorRefBase.Tell(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.ActorRefBase.yml","Akka.Actor.ActorRefBase.TellInternal(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.ActorRefBase.yml","Akka.Actor.ActorRefBase.ToString":"Akka.Actor.ActorRefBase.yml","Akka.Actor.ActorRefBase.Equals(System.Object)":"Akka.Actor.ActorRefBase.yml","Akka.Actor.ActorRefBase.GetHashCode":"Akka.Actor.ActorRefBase.yml","Akka.Actor.ActorRefBase.CompareTo(System.Object)":"Akka.Actor.ActorRefBase.yml","Akka.Actor.ActorRefBase.Equals(Akka.Actor.IActorRef)":"Akka.Actor.ActorRefBase.yml","Akka.Actor.ActorRefBase.CompareTo(Akka.Actor.IActorRef)":"Akka.Actor.ActorRefBase.yml","Akka.Actor.ActorRefBase.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.ActorRefBase.yml","Akka.Actor.ActorRefBase.Surrogate":"Akka.Actor.ActorRefBase.Surrogate.yml","Akka.Actor.ActorRefBase.Surrogate.#ctor(System.String)":"Akka.Actor.ActorRefBase.Surrogate.yml","Akka.Actor.ActorRefBase.Surrogate.Path":"Akka.Actor.ActorRefBase.Surrogate.yml","Akka.Actor.ActorRefBase.Surrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.ActorRefBase.Surrogate.yml","Akka.Actor.IInternalActorRef":"Akka.Actor.IInternalActorRef.yml","Akka.Actor.IInternalActorRef.Parent":"Akka.Actor.IInternalActorRef.yml","Akka.Actor.IInternalActorRef.Provider":"Akka.Actor.IInternalActorRef.yml","Akka.Actor.IInternalActorRef.IsTerminated":"Akka.Actor.IInternalActorRef.yml","Akka.Actor.IInternalActorRef.GetChild(System.Collections.Generic.IEnumerable{System.String})":"Akka.Actor.IInternalActorRef.yml","Akka.Actor.IInternalActorRef.Resume(System.Exception)":"Akka.Actor.IInternalActorRef.yml","Akka.Actor.IInternalActorRef.Start":"Akka.Actor.IInternalActorRef.yml","Akka.Actor.IInternalActorRef.Stop":"Akka.Actor.IInternalActorRef.yml","Akka.Actor.IInternalActorRef.Restart(System.Exception)":"Akka.Actor.IInternalActorRef.yml","Akka.Actor.IInternalActorRef.Suspend":"Akka.Actor.IInternalActorRef.yml","Akka.Actor.IInternalActorRef.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage,Akka.Actor.IActorRef)":"Akka.Actor.IInternalActorRef.yml","Akka.Actor.IInternalActorRef.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage)":"Akka.Actor.IInternalActorRef.yml","Akka.Actor.InternalActorRefBase":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.InternalActorRefBase.Parent":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.InternalActorRefBase.Provider":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.InternalActorRefBase.GetChild(System.Collections.Generic.IEnumerable{System.String})":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.InternalActorRefBase.Resume(System.Exception)":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.InternalActorRefBase.Start":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.InternalActorRefBase.Stop":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.InternalActorRefBase.Restart(System.Exception)":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.InternalActorRefBase.Suspend":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.InternalActorRefBase.IsTerminated":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.InternalActorRefBase.IsLocal":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.InternalActorRefBase.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage,Akka.Actor.IActorRef)":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.InternalActorRefBase.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage)":"Akka.Actor.InternalActorRefBase.yml","Akka.Actor.MinimalActorRef":"Akka.Actor.MinimalActorRef.yml","Akka.Actor.MinimalActorRef.Parent":"Akka.Actor.MinimalActorRef.yml","Akka.Actor.MinimalActorRef.GetChild(System.Collections.Generic.IEnumerable{System.String})":"Akka.Actor.MinimalActorRef.yml","Akka.Actor.MinimalActorRef.Resume(System.Exception)":"Akka.Actor.MinimalActorRef.yml","Akka.Actor.MinimalActorRef.Start":"Akka.Actor.MinimalActorRef.yml","Akka.Actor.MinimalActorRef.Stop":"Akka.Actor.MinimalActorRef.yml","Akka.Actor.MinimalActorRef.Restart(System.Exception)":"Akka.Actor.MinimalActorRef.yml","Akka.Actor.MinimalActorRef.Suspend":"Akka.Actor.MinimalActorRef.yml","Akka.Actor.MinimalActorRef.TellInternal(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.MinimalActorRef.yml","Akka.Actor.MinimalActorRef.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage)":"Akka.Actor.MinimalActorRef.yml","Akka.Actor.MinimalActorRef.IsLocal":"Akka.Actor.MinimalActorRef.yml","Akka.Actor.MinimalActorRef.IsTerminated":"Akka.Actor.MinimalActorRef.yml","Akka.Actor.Nobody":"Akka.Actor.Nobody.yml","Akka.Actor.Nobody.Instance":"Akka.Actor.Nobody.yml","Akka.Actor.Nobody.Path":"Akka.Actor.Nobody.yml","Akka.Actor.Nobody.Provider":"Akka.Actor.Nobody.yml","Akka.Actor.Nobody.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.Nobody.yml","Akka.Actor.Nobody.NobodySurrogate":"Akka.Actor.Nobody.NobodySurrogate.yml","Akka.Actor.Nobody.NobodySurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.Nobody.NobodySurrogate.yml","Akka.Actor.ActorRefWithCell":"Akka.Actor.ActorRefWithCell.yml","Akka.Actor.ActorRefWithCell.Underlying":"Akka.Actor.ActorRefWithCell.yml","Akka.Actor.ActorRefWithCell.Children":"Akka.Actor.ActorRefWithCell.yml","Akka.Actor.ActorRefWithCell.GetSingleChild(System.String)":"Akka.Actor.ActorRefWithCell.yml","Akka.Actor.ActorRefExtensions":"Akka.Actor.ActorRefExtensions.yml","Akka.Actor.ActorRefExtensions.IsNobody(Akka.Actor.IActorRef)":"Akka.Actor.ActorRefExtensions.yml","Akka.Actor.ActorRefFactoryExtensions":"Akka.Actor.ActorRefFactoryExtensions.yml","Akka.Actor.ActorRefFactoryExtensions.ActorOf``1(Akka.Actor.IActorRefFactory,System.String)":"Akka.Actor.ActorRefFactoryExtensions.yml","Akka.Actor.ActorRefFactoryExtensions.ActorSelection(Akka.Actor.IActorRefFactory,Akka.Actor.IActorRef,System.String)":"Akka.Actor.ActorRefFactoryExtensions.yml","Akka.Actor.ActorRefFactoryShared":"Akka.Actor.ActorRefFactoryShared.yml","Akka.Actor.ActorRefFactoryShared.ActorSelection(Akka.Actor.ActorPath,Akka.Actor.ActorSystem)":"Akka.Actor.ActorRefFactoryShared.yml","Akka.Actor.ActorRefFactoryShared.ActorSelection(System.String,Akka.Actor.ActorSystem,Akka.Actor.IActorRef)":"Akka.Actor.ActorRefFactoryShared.yml","Akka.Actor.ActorRefFactoryShared.ActorSelection(Akka.Actor.IActorRef,System.String)":"Akka.Actor.ActorRefFactoryShared.yml","Akka.Actor.IActorRefProvider":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.RootGuardian":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.RootGuardianAt(Akka.Actor.Address)":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.Guardian":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.SystemGuardian":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.DeadLetters":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.RootPath":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.Settings":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.Init(Akka.Actor.Internal.ActorSystemImpl)":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.Deployer":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.TempPath":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.TempContainer":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.RegisterTempActor(Akka.Actor.IInternalActorRef,Akka.Actor.ActorPath)":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.UnregisterTempActor(Akka.Actor.ActorPath)":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.ActorOf(Akka.Actor.Internal.ActorSystemImpl,Akka.Actor.Props,Akka.Actor.IInternalActorRef,Akka.Actor.ActorPath,System.Boolean,Akka.Actor.Deploy,System.Boolean,System.Boolean)":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.ResolveActorRef(System.String)":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.ResolveActorRef(Akka.Actor.ActorPath)":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.TerminationTask":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.GetExternalAddressFor(Akka.Actor.Address)":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.IActorRefProvider.DefaultAddress":"Akka.Actor.IActorRefProvider.yml","Akka.Actor.LocalActorRefProvider":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.#ctor(System.String,Akka.Actor.Settings,Akka.Event.EventStream)":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.#ctor(System.String,Akka.Actor.Settings,Akka.Event.EventStream,Akka.Actor.Deployer,System.Func{Akka.Actor.ActorPath,Akka.Actor.IInternalActorRef})":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.DeadLetters":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.Deployer":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.RootGuardian":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.RootPath":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.Settings":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.SystemGuardian":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.TempContainer":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.TerminationTask":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.Guardian":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.EventStream":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.TempPath":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.RegisterExtraName(System.String,Akka.Actor.IInternalActorRef)":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.RootGuardianAt(Akka.Actor.Address)":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.RegisterTempActor(Akka.Actor.IInternalActorRef,Akka.Actor.ActorPath)":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.UnregisterTempActor(Akka.Actor.ActorPath)":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.Init(Akka.Actor.Internal.ActorSystemImpl)":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.ResolveActorRef(System.String)":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.ResolveActorRef(Akka.Actor.ActorPath)":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.ActorOf(Akka.Actor.Internal.ActorSystemImpl,Akka.Actor.Props,Akka.Actor.IInternalActorRef,Akka.Actor.ActorPath,System.Boolean,Akka.Actor.Deploy,System.Boolean,System.Boolean)":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.GetExternalAddressFor(Akka.Actor.Address)":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.DefaultAddress":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.LocalActorRefProvider.Log":"Akka.Actor.LocalActorRefProvider.yml","Akka.Actor.ActorSelection":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.Anchor":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.Path":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.PathString":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.#ctor":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.#ctor(Akka.Actor.IActorRef,Akka.Actor.SelectionPathElement[])":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.#ctor(Akka.Actor.IActorRef,System.String)":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.#ctor(Akka.Actor.IActorRef,System.Collections.Generic.IEnumerable{System.String})":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.Tell(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.ResolveOne(System.TimeSpan)":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.Equals(System.Object)":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.Equals(Akka.Actor.ActorSelection)":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.GetHashCode":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelection.ToString":"Akka.Actor.ActorSelection.yml","Akka.Actor.ActorSelectionMessage":"Akka.Actor.ActorSelectionMessage.yml","Akka.Actor.ActorSelectionMessage.#ctor(System.Object,Akka.Actor.SelectionPathElement[],System.Boolean)":"Akka.Actor.ActorSelectionMessage.yml","Akka.Actor.ActorSelectionMessage.Message":"Akka.Actor.ActorSelectionMessage.yml","Akka.Actor.ActorSelectionMessage.Elements":"Akka.Actor.ActorSelectionMessage.yml","Akka.Actor.ActorSelectionMessage.WildCardFanOut":"Akka.Actor.ActorSelectionMessage.yml","Akka.Actor.ActorSelectionMessage.ToString":"Akka.Actor.ActorSelectionMessage.yml","Akka.Actor.SelectionPathElement":"Akka.Actor.SelectionPathElement.yml","Akka.Actor.SelectChildName":"Akka.Actor.SelectChildName.yml","Akka.Actor.SelectChildName.#ctor(System.String)":"Akka.Actor.SelectChildName.yml","Akka.Actor.SelectChildName.Name":"Akka.Actor.SelectChildName.yml","Akka.Actor.SelectChildName.ToString":"Akka.Actor.SelectChildName.yml","Akka.Actor.SelectChildPattern":"Akka.Actor.SelectChildPattern.yml","Akka.Actor.SelectChildPattern.#ctor(System.String)":"Akka.Actor.SelectChildPattern.yml","Akka.Actor.SelectChildPattern.PatternStr":"Akka.Actor.SelectChildPattern.yml","Akka.Actor.SelectChildPattern.ToString":"Akka.Actor.SelectChildPattern.yml","Akka.Actor.SelectParent":"Akka.Actor.SelectParent.yml","Akka.Actor.SelectParent.ToString":"Akka.Actor.SelectParent.yml","Akka.Actor.ActorSystem":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Settings":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Name":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Serialization":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.EventStream":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.DeadLetters":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Dispatchers":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Mailboxes":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Scheduler":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Log":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.StartTime":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Uptime":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Create(System.String,Akka.Configuration.Config)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Create(System.String)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.GetExtension(Akka.Actor.IExtensionId)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.GetExtension``1":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.HasExtension(System.Type)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.HasExtension``1":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.TryGetExtension(System.Type,System.Object@)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.TryGetExtension``1(``0@)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.RegisterOnTermination(System.Action)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Shutdown":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Terminate":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.TerminationTask":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.AwaitTermination":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.AwaitTermination(System.TimeSpan)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.AwaitTermination(System.TimeSpan,System.Threading.CancellationToken)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.WhenTerminated":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Stop(Akka.Actor.IActorRef)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.Dispose":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.RegisterExtension(Akka.Actor.IExtensionId)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.ActorOf(Akka.Actor.Props,System.String)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.ActorSelection(Akka.Actor.ActorPath)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.ActorSelection(System.String)":"Akka.Actor.ActorSystem.yml","Akka.Actor.ActorSystem.WaitForShutdown":"Akka.Actor.ActorSystem.yml","Akka.Actor.Address":"Akka.Actor.Address.yml","Akka.Actor.Address.AllSystems":"Akka.Actor.Address.yml","Akka.Actor.Address.#ctor(System.String,System.String,System.String,System.Nullable{System.Int32})":"Akka.Actor.Address.yml","Akka.Actor.Address.Host":"Akka.Actor.Address.yml","Akka.Actor.Address.Port":"Akka.Actor.Address.yml","Akka.Actor.Address.System":"Akka.Actor.Address.yml","Akka.Actor.Address.Protocol":"Akka.Actor.Address.yml","Akka.Actor.Address.HasLocalScope":"Akka.Actor.Address.yml","Akka.Actor.Address.HasGlobalScope":"Akka.Actor.Address.yml","Akka.Actor.Address.ToString":"Akka.Actor.Address.yml","Akka.Actor.Address.Equals(Akka.Actor.Address)":"Akka.Actor.Address.yml","Akka.Actor.Address.Equals(System.Object)":"Akka.Actor.Address.yml","Akka.Actor.Address.GetHashCode":"Akka.Actor.Address.yml","Akka.Actor.Address.Clone":"Akka.Actor.Address.yml","Akka.Actor.Address.WithProtocol(System.String)":"Akka.Actor.Address.yml","Akka.Actor.Address.WithSystem(System.String)":"Akka.Actor.Address.yml","Akka.Actor.Address.WithHost(System.String)":"Akka.Actor.Address.yml","Akka.Actor.Address.WithPort(System.Nullable{System.Int32})":"Akka.Actor.Address.yml","Akka.Actor.Address.op_Equality(Akka.Actor.Address,Akka.Actor.Address)":"Akka.Actor.Address.yml","Akka.Actor.Address.op_Inequality(Akka.Actor.Address,Akka.Actor.Address)":"Akka.Actor.Address.yml","Akka.Actor.Address.HostPort":"Akka.Actor.Address.yml","Akka.Actor.Address.Parse(System.String)":"Akka.Actor.Address.yml","Akka.Actor.Address.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.Address.yml","Akka.Actor.Address.AddressSurrogate":"Akka.Actor.Address.AddressSurrogate.yml","Akka.Actor.Address.AddressSurrogate.Protocol":"Akka.Actor.Address.AddressSurrogate.yml","Akka.Actor.Address.AddressSurrogate.System":"Akka.Actor.Address.AddressSurrogate.yml","Akka.Actor.Address.AddressSurrogate.Host":"Akka.Actor.Address.AddressSurrogate.yml","Akka.Actor.Address.AddressSurrogate.Port":"Akka.Actor.Address.AddressSurrogate.yml","Akka.Actor.Address.AddressSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.Address.AddressSurrogate.yml","Akka.Actor.RelativeActorPath":"Akka.Actor.RelativeActorPath.yml","Akka.Actor.RelativeActorPath.Unapply(System.String)":"Akka.Actor.RelativeActorPath.yml","Akka.Actor.DeadLetterMailbox":"Akka.Actor.DeadLetterMailbox.yml","Akka.Actor.DeadLetterMailbox.#ctor(Akka.Actor.IActorRef)":"Akka.Actor.DeadLetterMailbox.yml","Akka.Actor.Deploy":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.Local":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.NoDispatcherGiven":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.NoMailboxGiven":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.NoScopeGiven":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.None":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.#ctor":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.#ctor(System.String,Akka.Actor.Scope)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.#ctor(Akka.Actor.Scope)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.#ctor(Akka.Routing.RouterConfig,Akka.Actor.Scope)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.#ctor(Akka.Routing.RouterConfig)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.#ctor(System.String,Akka.Configuration.Config,Akka.Routing.RouterConfig,Akka.Actor.Scope,System.String)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.#ctor(System.String,Akka.Configuration.Config,Akka.Routing.RouterConfig,Akka.Actor.Scope,System.String,System.String)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.Path":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.Config":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.RouterConfig":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.Scope":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.Mailbox":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.Dispatcher":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.Equals(Akka.Actor.Deploy)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.WithFallback(Akka.Actor.Deploy)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.WithScope(Akka.Actor.Scope)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.WithMailbox(System.String)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.WithDispatcher(System.String)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.WithRouterConfig(Akka.Routing.RouterConfig)":"Akka.Actor.Deploy.yml","Akka.Actor.Deploy.DeploySurrogate":"Akka.Actor.Deploy.DeploySurrogate.yml","Akka.Actor.Deploy.DeploySurrogate.Scope":"Akka.Actor.Deploy.DeploySurrogate.yml","Akka.Actor.Deploy.DeploySurrogate.RouterConfig":"Akka.Actor.Deploy.DeploySurrogate.yml","Akka.Actor.Deploy.DeploySurrogate.Path":"Akka.Actor.Deploy.DeploySurrogate.yml","Akka.Actor.Deploy.DeploySurrogate.Config":"Akka.Actor.Deploy.DeploySurrogate.yml","Akka.Actor.Deploy.DeploySurrogate.Mailbox":"Akka.Actor.Deploy.DeploySurrogate.yml","Akka.Actor.Deploy.DeploySurrogate.Dispatcher":"Akka.Actor.Deploy.DeploySurrogate.yml","Akka.Actor.Deploy.DeploySurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.Deploy.DeploySurrogate.yml","Akka.Actor.ExtendedActorSystem":"Akka.Actor.ExtendedActorSystem.yml","Akka.Actor.ExtendedActorSystem.Provider":"Akka.Actor.ExtendedActorSystem.yml","Akka.Actor.ExtendedActorSystem.Guardian":"Akka.Actor.ExtendedActorSystem.yml","Akka.Actor.ExtendedActorSystem.LookupRoot":"Akka.Actor.ExtendedActorSystem.yml","Akka.Actor.ExtendedActorSystem.SystemGuardian":"Akka.Actor.ExtendedActorSystem.yml","Akka.Actor.ExtendedActorSystem.ActorPipelineResolver":"Akka.Actor.ExtendedActorSystem.yml","Akka.Actor.ExtendedActorSystem.SystemActorOf(Akka.Actor.Props,System.String)":"Akka.Actor.ExtendedActorSystem.yml","Akka.Actor.ExtendedActorSystem.SystemActorOf``1(System.String)":"Akka.Actor.ExtendedActorSystem.yml","Akka.Actor.ExtendedActorSystem.Abort":"Akka.Actor.ExtendedActorSystem.yml","Akka.Actor.Futures":"Akka.Actor.Futures.yml","Akka.Actor.Futures.Ask(Akka.Actor.ICanTell,System.Object,System.Nullable{System.TimeSpan})":"Akka.Actor.Futures.yml","Akka.Actor.Futures.Ask(Akka.Actor.ICanTell,System.Object,System.Threading.CancellationToken)":"Akka.Actor.Futures.yml","Akka.Actor.Futures.Ask(Akka.Actor.ICanTell,System.Object,System.Nullable{System.TimeSpan},System.Threading.CancellationToken)":"Akka.Actor.Futures.yml","Akka.Actor.Futures.Ask``1(Akka.Actor.ICanTell,System.Object,System.Nullable{System.TimeSpan})":"Akka.Actor.Futures.yml","Akka.Actor.Futures.Ask``1(Akka.Actor.ICanTell,System.Object,System.Threading.CancellationToken)":"Akka.Actor.Futures.yml","Akka.Actor.Futures.Ask``1(Akka.Actor.ICanTell,System.Object,System.Nullable{System.TimeSpan},System.Threading.CancellationToken)":"Akka.Actor.Futures.yml","Akka.Actor.IAutoReceivedMessage":"Akka.Actor.IAutoReceivedMessage.yml","Akka.Actor.Terminated":"Akka.Actor.Terminated.yml","Akka.Actor.Terminated.#ctor(Akka.Actor.IActorRef,System.Boolean,System.Boolean)":"Akka.Actor.Terminated.yml","Akka.Actor.Terminated.ActorRef":"Akka.Actor.Terminated.yml","Akka.Actor.Terminated.AddressTerminated":"Akka.Actor.Terminated.yml","Akka.Actor.Terminated.ExistenceConfirmed":"Akka.Actor.Terminated.yml","Akka.Actor.Terminated.ToString":"Akka.Actor.Terminated.yml","Akka.Actor.Identify":"Akka.Actor.Identify.yml","Akka.Actor.Identify.#ctor(System.Object)":"Akka.Actor.Identify.yml","Akka.Actor.Identify.MessageId":"Akka.Actor.Identify.yml","Akka.Actor.Identify.ToString":"Akka.Actor.Identify.yml","Akka.Actor.ActorIdentity":"Akka.Actor.ActorIdentity.yml","Akka.Actor.ActorIdentity.#ctor(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.ActorIdentity.yml","Akka.Actor.ActorIdentity.MessageId":"Akka.Actor.ActorIdentity.yml","Akka.Actor.ActorIdentity.Subject":"Akka.Actor.ActorIdentity.yml","Akka.Actor.ActorIdentity.ToString":"Akka.Actor.ActorIdentity.yml","Akka.Actor.PoisonPill":"Akka.Actor.PoisonPill.yml","Akka.Actor.PoisonPill.Instance":"Akka.Actor.PoisonPill.yml","Akka.Actor.PoisonPill.ToString":"Akka.Actor.PoisonPill.yml","Akka.Actor.Kill":"Akka.Actor.Kill.yml","Akka.Actor.Kill.Instance":"Akka.Actor.Kill.yml","Akka.Actor.Kill.ToString":"Akka.Actor.Kill.yml","Akka.Actor.EventStreamActor":"Akka.Actor.EventStreamActor.yml","Akka.Actor.EventStreamActor.Receive(System.Object)":"Akka.Actor.EventStreamActor.yml","Akka.Actor.GuardianActor":"Akka.Actor.GuardianActor.yml","Akka.Actor.GuardianActor.Receive(System.Object)":"Akka.Actor.GuardianActor.yml","Akka.Actor.GuardianActor.PreStart":"Akka.Actor.GuardianActor.yml","Akka.Actor.SystemGuardianActor":"Akka.Actor.SystemGuardianActor.yml","Akka.Actor.SystemGuardianActor.#ctor(Akka.Actor.IActorRef)":"Akka.Actor.SystemGuardianActor.yml","Akka.Actor.SystemGuardianActor.Receive(System.Object)":"Akka.Actor.SystemGuardianActor.yml","Akka.Actor.SystemGuardianActor.PreRestart(System.Exception,System.Object)":"Akka.Actor.SystemGuardianActor.yml","Akka.Actor.DeadLetterActorRef":"Akka.Actor.DeadLetterActorRef.yml","Akka.Actor.DeadLetterActorRef.#ctor(Akka.Actor.IActorRefProvider,Akka.Actor.ActorPath,Akka.Event.EventStream)":"Akka.Actor.DeadLetterActorRef.yml","Akka.Actor.DeadLetterActorRef.TellInternal(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.DeadLetterActorRef.yml","Akka.Actor.DeadLetterActorRef.SpecialHandle(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.DeadLetterActorRef.yml","Akka.Actor.ICell":"Akka.Actor.ICell.yml","Akka.Actor.ICell.Self":"Akka.Actor.ICell.yml","Akka.Actor.ICell.System":"Akka.Actor.ICell.yml","Akka.Actor.ICell.SystemImpl":"Akka.Actor.ICell.yml","Akka.Actor.ICell.Start":"Akka.Actor.ICell.yml","Akka.Actor.ICell.Suspend":"Akka.Actor.ICell.yml","Akka.Actor.ICell.Resume(System.Exception)":"Akka.Actor.ICell.yml","Akka.Actor.ICell.Restart(System.Exception)":"Akka.Actor.ICell.yml","Akka.Actor.ICell.Stop":"Akka.Actor.ICell.yml","Akka.Actor.ICell.Parent":"Akka.Actor.ICell.yml","Akka.Actor.ICell.IsLocal":"Akka.Actor.ICell.yml","Akka.Actor.ICell.Props":"Akka.Actor.ICell.yml","Akka.Actor.ICell.HasMessages":"Akka.Actor.ICell.yml","Akka.Actor.ICell.NumberOfMessages":"Akka.Actor.ICell.yml","Akka.Actor.ICell.IsTerminated":"Akka.Actor.ICell.yml","Akka.Actor.ICell.SendMessage(Akka.Actor.IActorRef,System.Object)":"Akka.Actor.ICell.yml","Akka.Actor.ICell.GetChildren":"Akka.Actor.ICell.yml","Akka.Actor.ICell.ChildrenContainer":"Akka.Actor.ICell.yml","Akka.Actor.ICell.GetSingleChild(System.String)":"Akka.Actor.ICell.yml","Akka.Actor.ICell.GetChildByName(System.String)":"Akka.Actor.ICell.yml","Akka.Actor.ICell.TryGetChildStatsByName(System.String,Akka.Actor.Internal.IChildStats@)":"Akka.Actor.ICell.yml","Akka.Actor.ICell.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage)":"Akka.Actor.ICell.yml","Akka.Actor.EmptyLocalActorRef":"Akka.Actor.EmptyLocalActorRef.yml","Akka.Actor.EmptyLocalActorRef.#ctor(Akka.Actor.IActorRefProvider,Akka.Actor.ActorPath,Akka.Event.EventStream)":"Akka.Actor.EmptyLocalActorRef.yml","Akka.Actor.EmptyLocalActorRef.Path":"Akka.Actor.EmptyLocalActorRef.yml","Akka.Actor.EmptyLocalActorRef.Provider":"Akka.Actor.EmptyLocalActorRef.yml","Akka.Actor.EmptyLocalActorRef.IsTerminated":"Akka.Actor.EmptyLocalActorRef.yml","Akka.Actor.EmptyLocalActorRef.TellInternal(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.EmptyLocalActorRef.yml","Akka.Actor.EmptyLocalActorRef.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage)":"Akka.Actor.EmptyLocalActorRef.yml","Akka.Actor.EmptyLocalActorRef.SpecialHandle(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.EmptyLocalActorRef.yml","Akka.Actor.ICanTell":"Akka.Actor.ICanTell.yml","Akka.Actor.ICanTell.Tell(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.ICanTell.yml","Akka.Actor.IInboxable":"Akka.Actor.IInboxable.yml","Akka.Actor.IInboxable.Receiver":"Akka.Actor.IInboxable.yml","Akka.Actor.IInboxable.Receive":"Akka.Actor.IInboxable.yml","Akka.Actor.IInboxable.Receive(System.TimeSpan)":"Akka.Actor.IInboxable.yml","Akka.Actor.IInboxable.ReceiveAsync":"Akka.Actor.IInboxable.yml","Akka.Actor.IInboxable.ReceiveAsync(System.TimeSpan)":"Akka.Actor.IInboxable.yml","Akka.Actor.IInboxable.ReceiveWhere(System.Predicate{System.Object})":"Akka.Actor.IInboxable.yml","Akka.Actor.IInboxable.ReceiveWhere(System.Predicate{System.Object},System.TimeSpan)":"Akka.Actor.IInboxable.yml","Akka.Actor.IInboxable.Send(Akka.Actor.IActorRef,System.Object)":"Akka.Actor.IInboxable.yml","Akka.Actor.Inbox":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.Create(Akka.Actor.ActorSystem)":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.Receiver":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.Watch(Akka.Actor.IActorRef)":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.Unwatch(Akka.Actor.IActorRef)":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.Send(Akka.Actor.IActorRef,System.Object)":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.Receive":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.Receive(System.TimeSpan)":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.ReceiveWhere(System.Predicate{System.Object})":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.ReceiveWhere(System.Predicate{System.Object},System.TimeSpan)":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.ReceiveAsync":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.ReceiveAsync(System.TimeSpan)":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.Dispose":"Akka.Actor.Inbox.yml","Akka.Actor.Inbox.Dispose(System.Boolean)":"Akka.Actor.Inbox.yml","Akka.Actor.LocalScope":"Akka.Actor.LocalScope.yml","Akka.Actor.LocalScope.Instance":"Akka.Actor.LocalScope.yml","Akka.Actor.LocalScope.WithFallback(Akka.Actor.Scope)":"Akka.Actor.LocalScope.yml","Akka.Actor.LocalScope.Copy":"Akka.Actor.LocalScope.yml","Akka.Actor.LocalScope.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.LocalScope.yml","Akka.Actor.LocalScope.LocalScopeSurrogate":"Akka.Actor.LocalScope.LocalScopeSurrogate.yml","Akka.Actor.LocalScope.LocalScopeSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.LocalScope.LocalScopeSurrogate.yml","Akka.Actor.NameAndUid":"Akka.Actor.NameAndUid.yml","Akka.Actor.NameAndUid.#ctor(System.String,System.Int32)":"Akka.Actor.NameAndUid.yml","Akka.Actor.NameAndUid.Name":"Akka.Actor.NameAndUid.yml","Akka.Actor.NameAndUid.Uid":"Akka.Actor.NameAndUid.yml","Akka.Actor.NameAndUid.ToString":"Akka.Actor.NameAndUid.yml","Akka.Actor.ReceiveTimeout":"Akka.Actor.ReceiveTimeout.yml","Akka.Actor.ReceiveTimeout.Instance":"Akka.Actor.ReceiveTimeout.yml","Akka.Actor.RemoteScope":"Akka.Actor.RemoteScope.yml","Akka.Actor.RemoteScope.#ctor":"Akka.Actor.RemoteScope.yml","Akka.Actor.RemoteScope.#ctor(Akka.Actor.Address)":"Akka.Actor.RemoteScope.yml","Akka.Actor.RemoteScope.Address":"Akka.Actor.RemoteScope.yml","Akka.Actor.RemoteScope.Equals(Akka.Actor.RemoteScope)":"Akka.Actor.RemoteScope.yml","Akka.Actor.RemoteScope.Equals(System.Object)":"Akka.Actor.RemoteScope.yml","Akka.Actor.RemoteScope.GetHashCode":"Akka.Actor.RemoteScope.yml","Akka.Actor.RemoteScope.WithFallback(Akka.Actor.Scope)":"Akka.Actor.RemoteScope.yml","Akka.Actor.RemoteScope.Copy":"Akka.Actor.RemoteScope.yml","Akka.Actor.RepointableActorRef":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.System":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Props":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Dispatcher":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Supervisor":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef._path":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.#ctor(Akka.Actor.Internal.ActorSystemImpl,Akka.Actor.Props,Akka.Dispatch.MessageDispatcher,Akka.Dispatch.MailboxType,Akka.Actor.IInternalActorRef,Akka.Actor.ActorPath)":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Underlying":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Lookup":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.IsTerminated":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.SwapUnderlying(Akka.Actor.ICell)":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Initialize(System.Boolean)":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Point":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.NewCell":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Path":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Parent":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Provider":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.IsLocal":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Start":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Suspend":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage)":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Resume(System.Exception)":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Stop":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Restart(System.Exception)":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.IsStarted":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.TellInternal(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.GetChild(System.Collections.Generic.IEnumerable{System.String})":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.GetSingleChild(System.String)":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.RepointableActorRef.Children":"Akka.Actor.RepointableActorRef.yml","Akka.Actor.UnstartedCell":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.#ctor(Akka.Actor.Internal.ActorSystemImpl,Akka.Actor.RepointableActorRef,Akka.Actor.Props,Akka.Actor.IInternalActorRef)":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.ReplaceWith(Akka.Actor.ICell)":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.System":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.SystemImpl":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.Start":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.Suspend":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.Resume(System.Exception)":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.Restart(System.Exception)":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.Stop":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.Parent":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.GetChildren":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.ChildrenContainer":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.GetSingleChild(System.String)":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.GetChildByName(System.String)":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.TryGetChildStatsByName(System.String,Akka.Actor.Internal.IChildStats@)":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.SendMessage(Akka.Actor.IActorRef,System.Object)":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage)":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.IsLocal":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.IsTerminated":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.HasMessages":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.NumberOfMessages":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.Self":"Akka.Actor.UnstartedCell.yml","Akka.Actor.UnstartedCell.Props":"Akka.Actor.UnstartedCell.yml","Akka.Actor.RootGuardianActorRef":"Akka.Actor.RootGuardianActorRef.yml","Akka.Actor.RootGuardianActorRef.#ctor(Akka.Actor.Internal.ActorSystemImpl,Akka.Actor.Props,Akka.Dispatch.MessageDispatcher,Akka.Dispatch.MailboxType,Akka.Actor.IInternalActorRef,Akka.Actor.ActorPath,Akka.Actor.IInternalActorRef,System.Collections.Generic.IReadOnlyDictionary{System.String,Akka.Actor.IInternalActorRef})":"Akka.Actor.RootGuardianActorRef.yml","Akka.Actor.RootGuardianActorRef.Parent":"Akka.Actor.RootGuardianActorRef.yml","Akka.Actor.RootGuardianActorRef.SetTempContainer(Akka.Actor.IInternalActorRef)":"Akka.Actor.RootGuardianActorRef.yml","Akka.Actor.RootGuardianActorRef.GetSingleChild(System.String)":"Akka.Actor.RootGuardianActorRef.yml","Akka.Actor.RootGuardianSupervisor":"Akka.Actor.RootGuardianSupervisor.yml","Akka.Actor.RootGuardianSupervisor.#ctor(Akka.Actor.RootActorPath,Akka.Actor.IActorRefProvider,System.Threading.Tasks.TaskCompletionSource{Akka.Actor.Status},Akka.Event.ILoggingAdapter)":"Akka.Actor.RootGuardianSupervisor.yml","Akka.Actor.RootGuardianSupervisor.TellInternal(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.RootGuardianSupervisor.yml","Akka.Actor.RootGuardianSupervisor.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage)":"Akka.Actor.RootGuardianSupervisor.yml","Akka.Actor.RootGuardianSupervisor.CauseOfTermination":"Akka.Actor.RootGuardianSupervisor.yml","Akka.Actor.RootGuardianSupervisor.Stop":"Akka.Actor.RootGuardianSupervisor.yml","Akka.Actor.RootGuardianSupervisor.Path":"Akka.Actor.RootGuardianSupervisor.yml","Akka.Actor.RootGuardianSupervisor.Provider":"Akka.Actor.RootGuardianSupervisor.yml","Akka.Actor.Deployer":"Akka.Actor.Deployer.yml","Akka.Actor.Deployer.Default":"Akka.Actor.Deployer.yml","Akka.Actor.Deployer.#ctor(Akka.Actor.Settings)":"Akka.Actor.Deployer.yml","Akka.Actor.Deployer.Lookup(Akka.Actor.ActorPath)":"Akka.Actor.Deployer.yml","Akka.Actor.Deployer.Lookup(System.Collections.Generic.IEnumerable{System.String})":"Akka.Actor.Deployer.yml","Akka.Actor.Deployer.Lookup(System.Collections.Generic.IEnumerator{System.String})":"Akka.Actor.Deployer.yml","Akka.Actor.Deployer.SetDeploy(Akka.Actor.Deploy)":"Akka.Actor.Deployer.yml","Akka.Actor.Deployer.ParseConfig(System.String,Akka.Configuration.Config)":"Akka.Actor.Deployer.yml","Akka.Actor.IExtension":"Akka.Actor.IExtension.yml","Akka.Actor.IExtensionId":"Akka.Actor.IExtensionId.yml","Akka.Actor.IExtensionId.Apply(Akka.Actor.ActorSystem)":"Akka.Actor.IExtensionId.yml","Akka.Actor.IExtensionId.Get(Akka.Actor.ActorSystem)":"Akka.Actor.IExtensionId.yml","Akka.Actor.IExtensionId.CreateExtension(Akka.Actor.ExtendedActorSystem)":"Akka.Actor.IExtensionId.yml","Akka.Actor.IExtensionId.ExtensionType":"Akka.Actor.IExtensionId.yml","Akka.Actor.IExtensionId`1":"Akka.Actor.IExtensionId-1.yml","Akka.Actor.IExtensionId`1.Apply(Akka.Actor.ActorSystem)":"Akka.Actor.IExtensionId-1.yml","Akka.Actor.IExtensionId`1.Get(Akka.Actor.ActorSystem)":"Akka.Actor.IExtensionId-1.yml","Akka.Actor.IExtensionId`1.CreateExtension(Akka.Actor.ExtendedActorSystem)":"Akka.Actor.IExtensionId-1.yml","Akka.Actor.ActorSystemWithExtensions":"Akka.Actor.ActorSystemWithExtensions.yml","Akka.Actor.ActorSystemWithExtensions.WithExtension``1(Akka.Actor.ActorSystem)":"Akka.Actor.ActorSystemWithExtensions.yml","Akka.Actor.ActorSystemWithExtensions.WithExtension``1(Akka.Actor.ActorSystem,System.Type)":"Akka.Actor.ActorSystemWithExtensions.yml","Akka.Actor.ActorSystemWithExtensions.WithExtension``2(Akka.Actor.ActorSystem)":"Akka.Actor.ActorSystemWithExtensions.yml","Akka.Actor.ExtensionIdProvider`1":"Akka.Actor.ExtensionIdProvider-1.yml","Akka.Actor.ExtensionIdProvider`1.Apply(Akka.Actor.ActorSystem)":"Akka.Actor.ExtensionIdProvider-1.yml","Akka.Actor.ExtensionIdProvider`1.Akka#Actor#IExtensionId#Get(Akka.Actor.ActorSystem)":"Akka.Actor.ExtensionIdProvider-1.yml","Akka.Actor.ExtensionIdProvider`1.Akka#Actor#IExtensionId#CreateExtension(Akka.Actor.ExtendedActorSystem)":"Akka.Actor.ExtensionIdProvider-1.yml","Akka.Actor.ExtensionIdProvider`1.ExtensionType":"Akka.Actor.ExtensionIdProvider-1.yml","Akka.Actor.ExtensionIdProvider`1.Akka#Actor#IExtensionId#Apply(Akka.Actor.ActorSystem)":"Akka.Actor.ExtensionIdProvider-1.yml","Akka.Actor.ExtensionIdProvider`1.Get(Akka.Actor.ActorSystem)":"Akka.Actor.ExtensionIdProvider-1.yml","Akka.Actor.ExtensionIdProvider`1.CreateExtension(Akka.Actor.ExtendedActorSystem)":"Akka.Actor.ExtensionIdProvider-1.yml","Akka.Actor.ExtensionIdProvider`1.Equals(System.Object)":"Akka.Actor.ExtensionIdProvider-1.yml","Akka.Actor.ExtensionIdProvider`1.GetHashCode":"Akka.Actor.ExtensionIdProvider-1.yml","Akka.Actor.FSMBase":"Akka.Actor.FSMBase.yml","Akka.Actor.FSMBase.CurrentState`1":"Akka.Actor.FSMBase.CurrentState-1.yml","Akka.Actor.FSMBase.CurrentState`1.#ctor(Akka.Actor.IActorRef,`0)":"Akka.Actor.FSMBase.CurrentState-1.yml","Akka.Actor.FSMBase.CurrentState`1.FsmRef":"Akka.Actor.FSMBase.CurrentState-1.yml","Akka.Actor.FSMBase.CurrentState`1.State":"Akka.Actor.FSMBase.CurrentState-1.yml","Akka.Actor.FSMBase.Transition`1":"Akka.Actor.FSMBase.Transition-1.yml","Akka.Actor.FSMBase.Transition`1.#ctor(Akka.Actor.IActorRef,`0,`0)":"Akka.Actor.FSMBase.Transition-1.yml","Akka.Actor.FSMBase.Transition`1.FsmRef":"Akka.Actor.FSMBase.Transition-1.yml","Akka.Actor.FSMBase.Transition`1.From":"Akka.Actor.FSMBase.Transition-1.yml","Akka.Actor.FSMBase.Transition`1.To":"Akka.Actor.FSMBase.Transition-1.yml","Akka.Actor.FSMBase.Transition`1.ToString":"Akka.Actor.FSMBase.Transition-1.yml","Akka.Actor.FSMBase.SubscribeTransitionCallBack":"Akka.Actor.FSMBase.SubscribeTransitionCallBack.yml","Akka.Actor.FSMBase.SubscribeTransitionCallBack.#ctor(Akka.Actor.IActorRef)":"Akka.Actor.FSMBase.SubscribeTransitionCallBack.yml","Akka.Actor.FSMBase.SubscribeTransitionCallBack.ActorRef":"Akka.Actor.FSMBase.SubscribeTransitionCallBack.yml","Akka.Actor.FSMBase.UnsubscribeTransitionCallBack":"Akka.Actor.FSMBase.UnsubscribeTransitionCallBack.yml","Akka.Actor.FSMBase.UnsubscribeTransitionCallBack.#ctor(Akka.Actor.IActorRef)":"Akka.Actor.FSMBase.UnsubscribeTransitionCallBack.yml","Akka.Actor.FSMBase.UnsubscribeTransitionCallBack.ActorRef":"Akka.Actor.FSMBase.UnsubscribeTransitionCallBack.yml","Akka.Actor.FSMBase.Reason":"Akka.Actor.FSMBase.Reason.yml","Akka.Actor.FSMBase.Normal":"Akka.Actor.FSMBase.Normal.yml","Akka.Actor.FSMBase.Shutdown":"Akka.Actor.FSMBase.Shutdown.yml","Akka.Actor.FSMBase.Failure":"Akka.Actor.FSMBase.Failure.yml","Akka.Actor.FSMBase.Failure.#ctor(System.Object)":"Akka.Actor.FSMBase.Failure.yml","Akka.Actor.FSMBase.Failure.Cause":"Akka.Actor.FSMBase.Failure.yml","Akka.Actor.FSMBase.StateTimeout":"Akka.Actor.FSMBase.StateTimeout.yml","Akka.Actor.FSMBase.LogEntry`2":"Akka.Actor.FSMBase.LogEntry-2.yml","Akka.Actor.FSMBase.LogEntry`2.#ctor(`0,`1,System.Object)":"Akka.Actor.FSMBase.LogEntry-2.yml","Akka.Actor.FSMBase.LogEntry`2.StateName":"Akka.Actor.FSMBase.LogEntry-2.yml","Akka.Actor.FSMBase.LogEntry`2.StateData":"Akka.Actor.FSMBase.LogEntry-2.yml","Akka.Actor.FSMBase.LogEntry`2.FsmEvent":"Akka.Actor.FSMBase.LogEntry-2.yml","Akka.Actor.FSMBase.State`2":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.#ctor(`0,`1,System.Nullable{System.TimeSpan},Akka.Actor.FSMBase.Reason,System.Collections.Generic.List{System.Object})":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.StateName":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.StateData":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.Timeout":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.StopReason":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.Replies":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.Copy(System.Nullable{System.TimeSpan},Akka.Actor.FSMBase.Reason,System.Collections.Generic.List{System.Object})":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.ForMax(System.TimeSpan)":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.Replying(System.Object)":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.Using(`1)":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.ToString":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.Equals(Akka.Actor.FSMBase.State{`0,`1})":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.Equals(System.Object)":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.State`2.GetHashCode":"Akka.Actor.FSMBase.State-2.yml","Akka.Actor.FSMBase.Event`1":"Akka.Actor.FSMBase.Event-1.yml","Akka.Actor.FSMBase.Event`1.#ctor(System.Object,`0)":"Akka.Actor.FSMBase.Event-1.yml","Akka.Actor.FSMBase.Event`1.FsmEvent":"Akka.Actor.FSMBase.Event-1.yml","Akka.Actor.FSMBase.Event`1.StateData":"Akka.Actor.FSMBase.Event-1.yml","Akka.Actor.FSMBase.Event`1.ToString":"Akka.Actor.FSMBase.Event-1.yml","Akka.Actor.FSMBase.StopEvent`2":"Akka.Actor.FSMBase.StopEvent-2.yml","Akka.Actor.FSMBase.StopEvent`2.#ctor(Akka.Actor.FSMBase.Reason,`0,`1)":"Akka.Actor.FSMBase.StopEvent-2.yml","Akka.Actor.FSMBase.StopEvent`2.Reason":"Akka.Actor.FSMBase.StopEvent-2.yml","Akka.Actor.FSMBase.StopEvent`2.TerminatedState":"Akka.Actor.FSMBase.StopEvent-2.yml","Akka.Actor.FSMBase.StopEvent`2.StateData":"Akka.Actor.FSMBase.StopEvent-2.yml","Akka.Actor.FSM`2":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.#ctor":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.When(`0,Akka.Actor.FSM{`0,`1}.StateFunction,System.Nullable{System.TimeSpan})":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.StartWith(`0,`1,System.Nullable{System.TimeSpan})":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.GoTo(`0)":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.GoTo(`0,`1)":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.Stay":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.Stop":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.Stop(Akka.Actor.FSMBase.Reason)":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.Stop(Akka.Actor.FSMBase.Reason,`1)":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.SetTimer(System.String,System.Object,System.TimeSpan,System.Boolean)":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.CancelTimer(System.String)":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.IsTimerActive(System.String)":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.SetStateTimeout(`0,System.Nullable{System.TimeSpan})":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.Akka#Actor#Internal#IInternalSupportsTestFSMRef{TState,TData}#IsStateTimerActive":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.OnTransition(Akka.Actor.FSM{`0,`1}.TransitionHandler)":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.OnTermination(System.Action{Akka.Actor.FSMBase.StopEvent{`0,`1}})":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.WhenUnhandled(Akka.Actor.FSM{`0,`1}.StateFunction)":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.Initialize":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.StateName":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.StateData":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.NextStateData":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.Transform(Akka.Actor.FSM{`0,`1}.StateFunction)":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.Listeners":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.DebugEvent":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.Receive(System.Object)":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.Akka#Actor#Internal#IInternalSupportsTestFSMRef{TState,TData}#ApplyState(Akka.Actor.FSMBase.State{`0,`1})":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.PostStop":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.LogTermination(Akka.Actor.FSMBase.Reason)":"Akka.Actor.FSM-2.yml","Akka.Actor.FSM`2.StateFunction":"Akka.Actor.FSM-2.StateFunction.yml","Akka.Actor.FSM`2.TransitionHandler":"Akka.Actor.FSM-2.TransitionHandler.yml","Akka.Actor.FSM`2.TransformHelper":"Akka.Actor.FSM-2.TransformHelper.yml","Akka.Actor.FSM`2.TransformHelper.#ctor(Akka.Actor.FSM{`0,`1}.StateFunction)":"Akka.Actor.FSM-2.TransformHelper.yml","Akka.Actor.FSM`2.TransformHelper.Func":"Akka.Actor.FSM-2.TransformHelper.yml","Akka.Actor.FSM`2.TransformHelper.Using(System.Func{Akka.Actor.FSMBase.State{`0,`1},Akka.Actor.FSMBase.State{`0,`1}})":"Akka.Actor.FSM-2.TransformHelper.yml","Akka.Actor.ILoggingFSM":"Akka.Actor.ILoggingFSM.yml","Akka.Actor.GracefulStopSupport":"Akka.Actor.GracefulStopSupport.yml","Akka.Actor.GracefulStopSupport.GracefulStop(Akka.Actor.IActorRef,System.TimeSpan)":"Akka.Actor.GracefulStopSupport.yml","Akka.Actor.GracefulStopSupport.GracefulStop(Akka.Actor.IActorRef,System.TimeSpan,System.Object)":"Akka.Actor.GracefulStopSupport.yml","Akka.Actor.IUntypedActorContext":"Akka.Actor.IUntypedActorContext.yml","Akka.Actor.IUntypedActorContext.Become(Akka.Actor.UntypedReceive,System.Boolean)":"Akka.Actor.IUntypedActorContext.yml","Akka.Actor.IUntypedActorContext.Become(Akka.Actor.UntypedReceive)":"Akka.Actor.IUntypedActorContext.yml","Akka.Actor.IUntypedActorContext.BecomeStacked(Akka.Actor.UntypedReceive)":"Akka.Actor.IUntypedActorContext.yml","Akka.Actor.INoSerializationVerificationNeeded":"Akka.Actor.INoSerializationVerificationNeeded.yml","Akka.Actor.IPossiblyHarmful":"Akka.Actor.IPossiblyHarmful.yml","Akka.Actor.PipeToSupport":"Akka.Actor.PipeToSupport.yml","Akka.Actor.PipeToSupport.PipeTo``1(System.Threading.Tasks.Task{``0},Akka.Actor.ICanTell,Akka.Actor.IActorRef,System.Func{``0,System.Object},System.Func{System.Exception,System.Object})":"Akka.Actor.PipeToSupport.yml","Akka.Actor.PipeToSupport.PipeTo(System.Threading.Tasks.Task,Akka.Actor.ICanTell,Akka.Actor.IActorRef)":"Akka.Actor.PipeToSupport.yml","Akka.Actor.Receive":"Akka.Actor.Receive.yml","Akka.Actor.ITellScheduler":"Akka.Actor.ITellScheduler.yml","Akka.Actor.ITellScheduler.ScheduleTellOnce(System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef)":"Akka.Actor.ITellScheduler.yml","Akka.Actor.ITellScheduler.ScheduleTellOnce(System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef,Akka.Actor.ICancelable)":"Akka.Actor.ITellScheduler.yml","Akka.Actor.ITellScheduler.ScheduleTellRepeatedly(System.TimeSpan,System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef)":"Akka.Actor.ITellScheduler.yml","Akka.Actor.ITellScheduler.ScheduleTellRepeatedly(System.TimeSpan,System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef,Akka.Actor.ICancelable)":"Akka.Actor.ITellScheduler.yml","Akka.Actor.HashedWheelTimerScheduler":"Akka.Actor.HashedWheelTimerScheduler.yml","Akka.Actor.HashedWheelTimerScheduler.#ctor(Akka.Configuration.Config,Akka.Event.ILoggingAdapter)":"Akka.Actor.HashedWheelTimerScheduler.yml","Akka.Actor.HashedWheelTimerScheduler.TimeNow":"Akka.Actor.HashedWheelTimerScheduler.yml","Akka.Actor.HashedWheelTimerScheduler.MonotonicClock":"Akka.Actor.HashedWheelTimerScheduler.yml","Akka.Actor.HashedWheelTimerScheduler.HighResMonotonicClock":"Akka.Actor.HashedWheelTimerScheduler.yml","Akka.Actor.HashedWheelTimerScheduler.InternalScheduleTellOnce(System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef,Akka.Actor.ICancelable)":"Akka.Actor.HashedWheelTimerScheduler.yml","Akka.Actor.HashedWheelTimerScheduler.InternalScheduleTellRepeatedly(System.TimeSpan,System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef,Akka.Actor.ICancelable)":"Akka.Actor.HashedWheelTimerScheduler.yml","Akka.Actor.HashedWheelTimerScheduler.InternalScheduleOnce(System.TimeSpan,System.Action,Akka.Actor.ICancelable)":"Akka.Actor.HashedWheelTimerScheduler.yml","Akka.Actor.HashedWheelTimerScheduler.InternalScheduleRepeatedly(System.TimeSpan,System.TimeSpan,System.Action,Akka.Actor.ICancelable)":"Akka.Actor.HashedWheelTimerScheduler.yml","Akka.Actor.HashedWheelTimerScheduler.Dispose":"Akka.Actor.HashedWheelTimerScheduler.yml","Akka.Actor.SchedulerBase":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.SchedulerConfig":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.Log":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.#ctor(Akka.Configuration.Config,Akka.Event.ILoggingAdapter)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.Akka#Actor#ITellScheduler#ScheduleTellOnce(System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.Akka#Actor#ITellScheduler#ScheduleTellOnce(System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef,Akka.Actor.ICancelable)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.Akka#Actor#ITellScheduler#ScheduleTellRepeatedly(System.TimeSpan,System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.Akka#Actor#ITellScheduler#ScheduleTellRepeatedly(System.TimeSpan,System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef,Akka.Actor.ICancelable)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.Akka#Actor#IActionScheduler#ScheduleOnce(System.TimeSpan,System.Action)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.Akka#Actor#IActionScheduler#ScheduleOnce(System.TimeSpan,System.Action,Akka.Actor.ICancelable)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.Akka#Actor#IActionScheduler#ScheduleRepeatedly(System.TimeSpan,System.TimeSpan,System.Action)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.Akka#Actor#IActionScheduler#ScheduleRepeatedly(System.TimeSpan,System.TimeSpan,System.Action,Akka.Actor.ICancelable)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.Akka#Actor#IScheduler#Advanced":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.Akka#Actor#ITimeProvider#Now":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.TimeNow":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.MonotonicClock":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.HighResMonotonicClock":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.InternalScheduleTellOnce(System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef,Akka.Actor.ICancelable)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.InternalScheduleTellRepeatedly(System.TimeSpan,System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef,Akka.Actor.ICancelable)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.InternalScheduleOnce(System.TimeSpan,System.Action,Akka.Actor.ICancelable)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.InternalScheduleRepeatedly(System.TimeSpan,System.TimeSpan,System.Action,Akka.Actor.ICancelable)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.ValidateInterval(System.TimeSpan,System.String)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerBase.ValidateDelay(System.TimeSpan,System.String)":"Akka.Actor.SchedulerBase.yml","Akka.Actor.SchedulerException":"Akka.Actor.SchedulerException.yml","Akka.Actor.SchedulerException.#ctor(System.String)":"Akka.Actor.SchedulerException.yml","Akka.Actor.SchedulerExtensions":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.SchedulerExtensions.ScheduleTellOnce(Akka.Actor.ITellScheduler,System.Int32,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef,Akka.Actor.ICancelable)":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.SchedulerExtensions.ScheduleTellRepeatedly(Akka.Actor.ITellScheduler,System.Int32,System.Int32,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef,Akka.Actor.ICancelable)":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.SchedulerExtensions.ScheduleOnce(Akka.Actor.IActionScheduler,System.Int32,System.Action,Akka.Actor.ICancelable)":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.SchedulerExtensions.ScheduleRepeatedly(Akka.Actor.IActionScheduler,System.Int32,System.Int32,System.Action,Akka.Actor.ICancelable)":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.SchedulerExtensions.ScheduleTellOnceCancelable(Akka.Actor.IScheduler,System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef)":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.SchedulerExtensions.ScheduleTellOnceCancelable(Akka.Actor.IScheduler,System.Int32,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef)":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.SchedulerExtensions.ScheduleTellRepeatedlyCancelable(Akka.Actor.IScheduler,System.TimeSpan,System.TimeSpan,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef)":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.SchedulerExtensions.ScheduleTellRepeatedlyCancelable(Akka.Actor.IScheduler,System.Int32,System.Int32,Akka.Actor.ICanTell,System.Object,Akka.Actor.IActorRef)":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.SchedulerExtensions.ScheduleOnceCancelable(Akka.Actor.IActionScheduler,System.TimeSpan,System.Action)":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.SchedulerExtensions.ScheduleOnceCancelable(Akka.Actor.IActionScheduler,System.Int32,System.Action)":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.SchedulerExtensions.ScheduleRepeatedlyCancelable(Akka.Actor.IActionScheduler,System.TimeSpan,System.TimeSpan,System.Action)":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.SchedulerExtensions.ScheduleRepeatedlyCancelable(Akka.Actor.IActionScheduler,System.Int32,System.Int32,System.Action)":"Akka.Actor.SchedulerExtensions.yml","Akka.Actor.Scope":"Akka.Actor.Scope.yml","Akka.Actor.Scope.Local":"Akka.Actor.Scope.yml","Akka.Actor.Scope.WithFallback(Akka.Actor.Scope)":"Akka.Actor.Scope.yml","Akka.Actor.Scope.Copy":"Akka.Actor.Scope.yml","Akka.Actor.Scope.Equals(Akka.Actor.Scope)":"Akka.Actor.Scope.yml","Akka.Actor.Settings":"Akka.Actor.Settings.yml","Akka.Actor.Settings.InjectTopLevelFallback(Akka.Configuration.Config)":"Akka.Actor.Settings.yml","Akka.Actor.Settings.#ctor(Akka.Actor.ActorSystem,Akka.Configuration.Config)":"Akka.Actor.Settings.yml","Akka.Actor.Settings.System":"Akka.Actor.Settings.yml","Akka.Actor.Settings.Config":"Akka.Actor.Settings.yml","Akka.Actor.Settings.ConfigVersion":"Akka.Actor.Settings.yml","Akka.Actor.Settings.ProviderClass":"Akka.Actor.Settings.yml","Akka.Actor.Settings.SupervisorStrategyClass":"Akka.Actor.Settings.yml","Akka.Actor.Settings.SerializeAllMessages":"Akka.Actor.Settings.yml","Akka.Actor.Settings.SerializeAllCreators":"Akka.Actor.Settings.yml","Akka.Actor.Settings.AskTimeout":"Akka.Actor.Settings.yml","Akka.Actor.Settings.CreationTimeout":"Akka.Actor.Settings.yml","Akka.Actor.Settings.UnstartedPushTimeout":"Akka.Actor.Settings.yml","Akka.Actor.Settings.LogLevel":"Akka.Actor.Settings.yml","Akka.Actor.Settings.StdoutLogLevel":"Akka.Actor.Settings.yml","Akka.Actor.Settings.Loggers":"Akka.Actor.Settings.yml","Akka.Actor.Settings.LoggersDispatcher":"Akka.Actor.Settings.yml","Akka.Actor.Settings.LoggerStartTimeout":"Akka.Actor.Settings.yml","Akka.Actor.Settings.LogConfigOnStart":"Akka.Actor.Settings.yml","Akka.Actor.Settings.LogDeadLetters":"Akka.Actor.Settings.yml","Akka.Actor.Settings.LogDeadLettersDuringShutdown":"Akka.Actor.Settings.yml","Akka.Actor.Settings.AddLoggingReceive":"Akka.Actor.Settings.yml","Akka.Actor.Settings.DebugAutoReceive":"Akka.Actor.Settings.yml","Akka.Actor.Settings.DebugEventStream":"Akka.Actor.Settings.yml","Akka.Actor.Settings.DebugUnhandledMessage":"Akka.Actor.Settings.yml","Akka.Actor.Settings.DebugRouterMisconfiguration":"Akka.Actor.Settings.yml","Akka.Actor.Settings.Home":"Akka.Actor.Settings.yml","Akka.Actor.Settings.DebugLifecycle":"Akka.Actor.Settings.yml","Akka.Actor.Settings.FsmDebugEvent":"Akka.Actor.Settings.yml","Akka.Actor.Settings.DefaultVirtualNodesFactor":"Akka.Actor.Settings.yml","Akka.Actor.Settings.SchedulerClass":"Akka.Actor.Settings.yml","Akka.Actor.Settings.SchedulerShutdownTimeout":"Akka.Actor.Settings.yml","Akka.Actor.Settings.ToString":"Akka.Actor.Settings.yml","Akka.Actor.IActorStash":"Akka.Actor.IActorStash.yml","Akka.Actor.IActorStash.Stash":"Akka.Actor.IActorStash.yml","Akka.Actor.ActorStashPlugin":"Akka.Actor.ActorStashPlugin.yml","Akka.Actor.ActorStashPlugin.CanBeAppliedTo(System.Type)":"Akka.Actor.ActorStashPlugin.yml","Akka.Actor.ActorStashPlugin.AfterIncarnated(Akka.Actor.ActorBase,Akka.Actor.IActorContext)":"Akka.Actor.ActorStashPlugin.yml","Akka.Actor.ActorStashPlugin.BeforeIncarnated(Akka.Actor.ActorBase,Akka.Actor.IActorContext)":"Akka.Actor.ActorStashPlugin.yml","Akka.Actor.IStash":"Akka.Actor.IStash.yml","Akka.Actor.IStash.Stash":"Akka.Actor.IStash.yml","Akka.Actor.IStash.Unstash":"Akka.Actor.IStash.yml","Akka.Actor.IStash.UnstashAll":"Akka.Actor.IStash.yml","Akka.Actor.IStash.UnstashAll(System.Func{Akka.Actor.Envelope,System.Boolean})":"Akka.Actor.IStash.yml","Akka.Actor.IStash.ClearStash":"Akka.Actor.IStash.yml","Akka.Actor.IStash.Prepend(System.Collections.Generic.IEnumerable{Akka.Actor.Envelope})":"Akka.Actor.IStash.yml","Akka.Actor.UntypedActorWithBoundedStash":"Akka.Actor.UntypedActorWithBoundedStash.yml","Akka.Actor.UntypedActorWithBoundedStash.CurrentStash":"Akka.Actor.UntypedActorWithBoundedStash.yml","Akka.Actor.UntypedActorWithBoundedStash.Akka#Actor#IActorStash#Stash":"Akka.Actor.UntypedActorWithBoundedStash.yml","Akka.Actor.UntypedActorWithBoundedStash.Stash":"Akka.Actor.UntypedActorWithBoundedStash.yml","Akka.Actor.UntypedActorWithBoundedStash.Unstash":"Akka.Actor.UntypedActorWithBoundedStash.yml","Akka.Actor.UntypedActorWithBoundedStash.UnstashAll":"Akka.Actor.UntypedActorWithBoundedStash.yml","Akka.Actor.UntypedActorWithBoundedStash.UnstashAll(System.Func{Akka.Actor.Envelope,System.Boolean})":"Akka.Actor.UntypedActorWithBoundedStash.yml","Akka.Actor.UntypedActorWithBoundedStash.PreRestart(System.Exception,System.Object)":"Akka.Actor.UntypedActorWithBoundedStash.yml","Akka.Actor.UntypedActorWithBoundedStash.PostStop":"Akka.Actor.UntypedActorWithBoundedStash.yml","Akka.Actor.StashFactory":"Akka.Actor.StashFactory.yml","Akka.Actor.StashFactory.CreateStash``1(Akka.Actor.IActorContext)":"Akka.Actor.StashFactory.yml","Akka.Actor.StashFactory.CreateStash(Akka.Actor.IActorContext,Akka.Actor.IActorStash)":"Akka.Actor.StashFactory.yml","Akka.Actor.StashFactory.CreateStash(Akka.Actor.IActorContext,System.Type)":"Akka.Actor.StashFactory.yml","Akka.Actor.StashOverflowException":"Akka.Actor.StashOverflowException.yml","Akka.Actor.StashOverflowException.#ctor(System.String,System.Exception)":"Akka.Actor.StashOverflowException.yml","Akka.Actor.StashOverflowException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.StashOverflowException.yml","Akka.Actor.UntypedActorWithUnboundedStash":"Akka.Actor.UntypedActorWithUnboundedStash.yml","Akka.Actor.UntypedActorWithUnboundedStash.CurrentStash":"Akka.Actor.UntypedActorWithUnboundedStash.yml","Akka.Actor.UntypedActorWithUnboundedStash.Akka#Actor#IActorStash#Stash":"Akka.Actor.UntypedActorWithUnboundedStash.yml","Akka.Actor.UntypedActorWithUnboundedStash.Stash":"Akka.Actor.UntypedActorWithUnboundedStash.yml","Akka.Actor.UntypedActorWithUnboundedStash.Unstash":"Akka.Actor.UntypedActorWithUnboundedStash.yml","Akka.Actor.UntypedActorWithUnboundedStash.UnstashAll":"Akka.Actor.UntypedActorWithUnboundedStash.yml","Akka.Actor.UntypedActorWithUnboundedStash.UnstashAll(System.Func{Akka.Actor.Envelope,System.Boolean})":"Akka.Actor.UntypedActorWithUnboundedStash.yml","Akka.Actor.UntypedActorWithUnboundedStash.PreRestart(System.Exception,System.Object)":"Akka.Actor.UntypedActorWithUnboundedStash.yml","Akka.Actor.UntypedActorWithUnboundedStash.PostStop":"Akka.Actor.UntypedActorWithUnboundedStash.yml","Akka.Actor.IWithBoundedStash":"Akka.Actor.IWithBoundedStash.yml","Akka.Actor.IWithUnboundedStash":"Akka.Actor.IWithUnboundedStash.yml","Akka.Actor.AkkaException":"Akka.Actor.AkkaException.yml","Akka.Actor.AkkaException.#ctor":"Akka.Actor.AkkaException.yml","Akka.Actor.AkkaException.#ctor(System.String,System.Exception)":"Akka.Actor.AkkaException.yml","Akka.Actor.AkkaException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.AkkaException.yml","Akka.Actor.AkkaException.Cause":"Akka.Actor.AkkaException.yml","Akka.Actor.InvalidActorNameException":"Akka.Actor.InvalidActorNameException.yml","Akka.Actor.InvalidActorNameException.#ctor(System.String)":"Akka.Actor.InvalidActorNameException.yml","Akka.Actor.InvalidActorNameException.#ctor(System.String,System.Exception)":"Akka.Actor.InvalidActorNameException.yml","Akka.Actor.InvalidActorNameException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.InvalidActorNameException.yml","Akka.Actor.AskTimeoutException":"Akka.Actor.AskTimeoutException.yml","Akka.Actor.AskTimeoutException.#ctor(System.String)":"Akka.Actor.AskTimeoutException.yml","Akka.Actor.AskTimeoutException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.AskTimeoutException.yml","Akka.Actor.ActorInterruptedException":"Akka.Actor.ActorInterruptedException.yml","Akka.Actor.ActorInterruptedException.#ctor(System.String,System.Exception)":"Akka.Actor.ActorInterruptedException.yml","Akka.Actor.ActorInitializationException":"Akka.Actor.ActorInitializationException.yml","Akka.Actor.ActorInitializationException.#ctor":"Akka.Actor.ActorInitializationException.yml","Akka.Actor.ActorInitializationException.#ctor(System.String)":"Akka.Actor.ActorInitializationException.yml","Akka.Actor.ActorInitializationException.#ctor(System.String,System.Exception)":"Akka.Actor.ActorInitializationException.yml","Akka.Actor.ActorInitializationException.#ctor(Akka.Actor.IActorRef,System.String,System.Exception)":"Akka.Actor.ActorInitializationException.yml","Akka.Actor.ActorInitializationException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.ActorInitializationException.yml","Akka.Actor.ActorInitializationException.Actor":"Akka.Actor.ActorInitializationException.yml","Akka.Actor.ActorInitializationException.ToString":"Akka.Actor.ActorInitializationException.yml","Akka.Actor.LoggerInitializationException":"Akka.Actor.LoggerInitializationException.yml","Akka.Actor.LoggerInitializationException.#ctor":"Akka.Actor.LoggerInitializationException.yml","Akka.Actor.LoggerInitializationException.#ctor(System.String)":"Akka.Actor.LoggerInitializationException.yml","Akka.Actor.LoggerInitializationException.#ctor(System.String,System.Exception)":"Akka.Actor.LoggerInitializationException.yml","Akka.Actor.LoggerInitializationException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.LoggerInitializationException.yml","Akka.Actor.ActorKilledException":"Akka.Actor.ActorKilledException.yml","Akka.Actor.ActorKilledException.#ctor(System.String)":"Akka.Actor.ActorKilledException.yml","Akka.Actor.ActorKilledException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.ActorKilledException.yml","Akka.Actor.IllegalActorStateException":"Akka.Actor.IllegalActorStateException.yml","Akka.Actor.IllegalActorStateException.#ctor(System.String)":"Akka.Actor.IllegalActorStateException.yml","Akka.Actor.IllegalActorStateException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.IllegalActorStateException.yml","Akka.Actor.IllegalActorNameException":"Akka.Actor.IllegalActorNameException.yml","Akka.Actor.IllegalActorNameException.#ctor(System.String)":"Akka.Actor.IllegalActorNameException.yml","Akka.Actor.IllegalActorNameException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.IllegalActorNameException.yml","Akka.Actor.DeathPactException":"Akka.Actor.DeathPactException.yml","Akka.Actor.DeathPactException.#ctor(Akka.Actor.IActorRef)":"Akka.Actor.DeathPactException.yml","Akka.Actor.DeathPactException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.DeathPactException.yml","Akka.Actor.DeathPactException.DeadActor":"Akka.Actor.DeathPactException.yml","Akka.Actor.PreRestartException":"Akka.Actor.PreRestartException.yml","Akka.Actor.PreRestartException.#ctor(Akka.Actor.IActorRef,System.Exception,System.Exception,System.Object)":"Akka.Actor.PreRestartException.yml","Akka.Actor.PreRestartException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.PreRestartException.yml","Akka.Actor.PostRestartException":"Akka.Actor.PostRestartException.yml","Akka.Actor.PostRestartException.#ctor(Akka.Actor.IActorRef,System.Exception,System.Exception)":"Akka.Actor.PostRestartException.yml","Akka.Actor.PostRestartException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.PostRestartException.yml","Akka.Actor.PostRestartException.OriginalCause":"Akka.Actor.PostRestartException.yml","Akka.Actor.ActorNotFoundException":"Akka.Actor.ActorNotFoundException.yml","Akka.Actor.ActorNotFoundException.#ctor":"Akka.Actor.ActorNotFoundException.yml","Akka.Actor.ActorNotFoundException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.ActorNotFoundException.yml","Akka.Actor.ActorNotFoundException.#ctor(System.String,System.Exception)":"Akka.Actor.ActorNotFoundException.yml","Akka.Actor.InvalidMessageException":"Akka.Actor.InvalidMessageException.yml","Akka.Actor.InvalidMessageException.#ctor":"Akka.Actor.InvalidMessageException.yml","Akka.Actor.InvalidMessageException.#ctor(System.String)":"Akka.Actor.InvalidMessageException.yml","Akka.Actor.InvalidMessageException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Actor.InvalidMessageException.yml","Akka.Actor.ICanWatch":"Akka.Actor.ICanWatch.yml","Akka.Actor.ICanWatch.Watch(Akka.Actor.IActorRef)":"Akka.Actor.ICanWatch.yml","Akka.Actor.ICanWatch.Unwatch(Akka.Actor.IActorRef)":"Akka.Actor.ICanWatch.yml","Akka.Actor.IActorContext":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.Self":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.Props":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.Dispatcher":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.Sender":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.System":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.Parent":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.Become(Akka.Actor.Receive)":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.BecomeStacked(Akka.Actor.Receive)":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.Become(Akka.Actor.Receive,System.Boolean)":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.UnbecomeStacked":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.Unbecome":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.Child(System.String)":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.GetChildren":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.SetReceiveTimeout(System.Nullable{System.TimeSpan})":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.ReceiveTimeout":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorContext.Stop(Akka.Actor.IActorRef)":"Akka.Actor.IActorContext.yml","Akka.Actor.IActorRefFactory":"Akka.Actor.IActorRefFactory.yml","Akka.Actor.IActorRefFactory.ActorOf(Akka.Actor.Props,System.String)":"Akka.Actor.IActorRefFactory.yml","Akka.Actor.IActorRefFactory.ActorSelection(Akka.Actor.ActorPath)":"Akka.Actor.IActorRefFactory.yml","Akka.Actor.IActorRefFactory.ActorSelection(System.String)":"Akka.Actor.IActorRefFactory.yml","Akka.Actor.Props":"Akka.Actor.Props.yml","Akka.Actor.Props.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.Props.yml","Akka.Actor.Props.Equals(Akka.Actor.Props)":"Akka.Actor.Props.yml","Akka.Actor.Props.Equals(System.Object)":"Akka.Actor.Props.yml","Akka.Actor.Props.GetHashCode":"Akka.Actor.Props.yml","Akka.Actor.Props.None":"Akka.Actor.Props.yml","Akka.Actor.Props.#ctor":"Akka.Actor.Props.yml","Akka.Actor.Props.#ctor(Akka.Actor.Props)":"Akka.Actor.Props.yml","Akka.Actor.Props.#ctor(System.Type,System.Object[])":"Akka.Actor.Props.yml","Akka.Actor.Props.#ctor(System.Type)":"Akka.Actor.Props.yml","Akka.Actor.Props.#ctor(System.Type,Akka.Actor.SupervisorStrategy,System.Collections.Generic.IEnumerable{System.Object})":"Akka.Actor.Props.yml","Akka.Actor.Props.#ctor(System.Type,Akka.Actor.SupervisorStrategy,System.Object[])":"Akka.Actor.Props.yml","Akka.Actor.Props.#ctor(Akka.Actor.Deploy,System.Type,System.Collections.Generic.IEnumerable{System.Object})":"Akka.Actor.Props.yml","Akka.Actor.Props.#ctor(Akka.Actor.Deploy,System.Type,System.Object[])":"Akka.Actor.Props.yml","Akka.Actor.Props.Type":"Akka.Actor.Props.yml","Akka.Actor.Props.Dispatcher":"Akka.Actor.Props.yml","Akka.Actor.Props.Mailbox":"Akka.Actor.Props.yml","Akka.Actor.Props.TypeName":"Akka.Actor.Props.yml","Akka.Actor.Props.RouterConfig":"Akka.Actor.Props.yml","Akka.Actor.Props.Deploy":"Akka.Actor.Props.yml","Akka.Actor.Props.SupervisorStrategy":"Akka.Actor.Props.yml","Akka.Actor.Props.Empty":"Akka.Actor.Props.yml","Akka.Actor.Props.Arguments":"Akka.Actor.Props.yml","Akka.Actor.Props.Create``1(System.Linq.Expressions.Expression{System.Func{``0}},Akka.Actor.SupervisorStrategy)":"Akka.Actor.Props.yml","Akka.Actor.Props.Create``1(System.Object[])":"Akka.Actor.Props.yml","Akka.Actor.Props.CreateBy``1(System.Object[])":"Akka.Actor.Props.yml","Akka.Actor.Props.Create``1(Akka.Actor.SupervisorStrategy)":"Akka.Actor.Props.yml","Akka.Actor.Props.Create(System.Type,System.Object[])":"Akka.Actor.Props.yml","Akka.Actor.Props.WithMailbox(System.String)":"Akka.Actor.Props.yml","Akka.Actor.Props.WithDispatcher(System.String)":"Akka.Actor.Props.yml","Akka.Actor.Props.WithRouter(Akka.Routing.RouterConfig)":"Akka.Actor.Props.yml","Akka.Actor.Props.WithDeploy(Akka.Actor.Deploy)":"Akka.Actor.Props.yml","Akka.Actor.Props.WithSupervisorStrategy(Akka.Actor.SupervisorStrategy)":"Akka.Actor.Props.yml","Akka.Actor.Props.NewActor":"Akka.Actor.Props.yml","Akka.Actor.Props.Copy":"Akka.Actor.Props.yml","Akka.Actor.Props.PropsSurrogate":"Akka.Actor.Props.PropsSurrogate.yml","Akka.Actor.Props.PropsSurrogate.Type":"Akka.Actor.Props.PropsSurrogate.yml","Akka.Actor.Props.PropsSurrogate.Deploy":"Akka.Actor.Props.PropsSurrogate.yml","Akka.Actor.Props.PropsSurrogate.Arguments":"Akka.Actor.Props.PropsSurrogate.yml","Akka.Actor.Props.PropsSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.Props.PropsSurrogate.yml","Akka.Actor.TerminatedProps":"Akka.Actor.TerminatedProps.yml","Akka.Actor.TerminatedProps.NewActor":"Akka.Actor.TerminatedProps.yml","Akka.Actor.IIndirectActorProducer":"Akka.Actor.IIndirectActorProducer.yml","Akka.Actor.IIndirectActorProducer.Produce":"Akka.Actor.IIndirectActorProducer.yml","Akka.Actor.IIndirectActorProducer.ActorType":"Akka.Actor.IIndirectActorProducer.yml","Akka.Actor.IIndirectActorProducer.Release(Akka.Actor.ActorBase)":"Akka.Actor.IIndirectActorProducer.yml","Akka.Actor.SupervisorStrategy":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.Decider":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.Handle(Akka.Actor.IActorRef,System.Exception)":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.HandleFailure(Akka.Actor.ActorCell,System.Exception,Akka.Actor.Internal.ChildRestartStats,System.Collections.Generic.IReadOnlyCollection{Akka.Actor.Internal.ChildRestartStats})":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.HandleFailure(Akka.Actor.ActorCell,Akka.Actor.IActorRef,System.Exception,Akka.Actor.Internal.ChildRestartStats,System.Collections.Generic.IReadOnlyCollection{Akka.Actor.Internal.ChildRestartStats})":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.DefaultDecider":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.RestartChild(Akka.Actor.IActorRef,System.Exception,System.Boolean)":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.ProcessFailure(Akka.Actor.IActorContext,System.Boolean,System.Exception,Akka.Actor.Internal.ChildRestartStats,System.Collections.Generic.IReadOnlyCollection{Akka.Actor.Internal.ChildRestartStats})":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.ProcessFailure(Akka.Actor.IActorContext,System.Boolean,Akka.Actor.IActorRef,System.Exception,Akka.Actor.Internal.ChildRestartStats,System.Collections.Generic.IReadOnlyCollection{Akka.Actor.Internal.ChildRestartStats})":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.ResumeChild(Akka.Actor.IActorRef,System.Exception)":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.LogFailure(Akka.Actor.IActorContext,Akka.Actor.IActorRef,System.Exception,Akka.Actor.Directive)":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.LoggingEnabled":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.DefaultStrategy":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.StoppingStrategy":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.HandleChildTerminated(Akka.Actor.IActorContext,Akka.Actor.IActorRef,System.Collections.Generic.IEnumerable{Akka.Actor.IInternalActorRef})":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.SupervisorStrategy.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.SupervisorStrategy.yml","Akka.Actor.OneForOneStrategy":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.MaxNumberOfRetries":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.WithinTimeRangeMilliseconds":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.Decider":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.#ctor(System.Nullable{System.Int32},System.Nullable{System.TimeSpan},System.Func{System.Exception,Akka.Actor.Directive})":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.#ctor(System.Nullable{System.Int32},System.Nullable{System.TimeSpan},Akka.Actor.IDecider)":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.#ctor(System.Int32,System.Int32,System.Func{System.Exception,Akka.Actor.Directive},System.Boolean)":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.#ctor(System.Int32,System.Int32,Akka.Actor.IDecider,System.Boolean)":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.#ctor(System.Func{System.Exception,Akka.Actor.Directive})":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.#ctor(System.Func{System.Exception,Akka.Actor.Directive},System.Boolean)":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.#ctor(Akka.Actor.IDecider)":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.#ctor":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.Handle(Akka.Actor.IActorRef,System.Exception)":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.ProcessFailure(Akka.Actor.IActorContext,System.Boolean,System.Exception,Akka.Actor.Internal.ChildRestartStats,System.Collections.Generic.IReadOnlyCollection{Akka.Actor.Internal.ChildRestartStats})":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.ProcessFailure(Akka.Actor.IActorContext,System.Boolean,Akka.Actor.IActorRef,System.Exception,Akka.Actor.Internal.ChildRestartStats,System.Collections.Generic.IReadOnlyCollection{Akka.Actor.Internal.ChildRestartStats})":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.HandleChildTerminated(Akka.Actor.IActorContext,Akka.Actor.IActorRef,System.Collections.Generic.IEnumerable{Akka.Actor.IInternalActorRef})":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.Equals(Akka.Actor.OneForOneStrategy)":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.Equals(System.Object)":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.GetHashCode":"Akka.Actor.OneForOneStrategy.yml","Akka.Actor.OneForOneStrategy.OneForOneStrategySurrogate":"Akka.Actor.OneForOneStrategy.OneForOneStrategySurrogate.yml","Akka.Actor.OneForOneStrategy.OneForOneStrategySurrogate.MaxNumberOfRetries":"Akka.Actor.OneForOneStrategy.OneForOneStrategySurrogate.yml","Akka.Actor.OneForOneStrategy.OneForOneStrategySurrogate.WithinTimeRangeMilliseconds":"Akka.Actor.OneForOneStrategy.OneForOneStrategySurrogate.yml","Akka.Actor.OneForOneStrategy.OneForOneStrategySurrogate.Decider":"Akka.Actor.OneForOneStrategy.OneForOneStrategySurrogate.yml","Akka.Actor.OneForOneStrategy.OneForOneStrategySurrogate.LoggingEnabled":"Akka.Actor.OneForOneStrategy.OneForOneStrategySurrogate.yml","Akka.Actor.OneForOneStrategy.OneForOneStrategySurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.OneForOneStrategy.OneForOneStrategySurrogate.yml","Akka.Actor.AllForOneStrategy":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.MaxNumberOfRetries":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.WithinTimeRangeMilliseconds":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.Decider":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.#ctor(System.Nullable{System.Int32},System.Nullable{System.TimeSpan},System.Func{System.Exception,Akka.Actor.Directive})":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.#ctor(System.Nullable{System.Int32},System.Nullable{System.TimeSpan},Akka.Actor.IDecider)":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.#ctor(System.Int32,System.Int32,System.Func{System.Exception,Akka.Actor.Directive},System.Boolean)":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.#ctor(System.Int32,System.Int32,Akka.Actor.IDecider,System.Boolean)":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.#ctor(System.Func{System.Exception,Akka.Actor.Directive})":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.#ctor(Akka.Actor.IDecider)":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.#ctor":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.Handle(Akka.Actor.IActorRef,System.Exception)":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.ProcessFailure(Akka.Actor.IActorContext,System.Boolean,System.Exception,Akka.Actor.Internal.ChildRestartStats,System.Collections.Generic.IReadOnlyCollection{Akka.Actor.Internal.ChildRestartStats})":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.ProcessFailure(Akka.Actor.IActorContext,System.Boolean,Akka.Actor.IActorRef,System.Exception,Akka.Actor.Internal.ChildRestartStats,System.Collections.Generic.IReadOnlyCollection{Akka.Actor.Internal.ChildRestartStats})":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.HandleChildTerminated(Akka.Actor.IActorContext,Akka.Actor.IActorRef,System.Collections.Generic.IEnumerable{Akka.Actor.IInternalActorRef})":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.Equals(Akka.Actor.AllForOneStrategy)":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.Equals(System.Object)":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.GetHashCode":"Akka.Actor.AllForOneStrategy.yml","Akka.Actor.AllForOneStrategy.AllForOneStrategySurrogate":"Akka.Actor.AllForOneStrategy.AllForOneStrategySurrogate.yml","Akka.Actor.AllForOneStrategy.AllForOneStrategySurrogate.MaxNumberOfRetries":"Akka.Actor.AllForOneStrategy.AllForOneStrategySurrogate.yml","Akka.Actor.AllForOneStrategy.AllForOneStrategySurrogate.WithinTimeRangeMilliseconds":"Akka.Actor.AllForOneStrategy.AllForOneStrategySurrogate.yml","Akka.Actor.AllForOneStrategy.AllForOneStrategySurrogate.Decider":"Akka.Actor.AllForOneStrategy.AllForOneStrategySurrogate.yml","Akka.Actor.AllForOneStrategy.AllForOneStrategySurrogate.LoggingEnabled":"Akka.Actor.AllForOneStrategy.AllForOneStrategySurrogate.yml","Akka.Actor.AllForOneStrategy.AllForOneStrategySurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Actor.AllForOneStrategy.AllForOneStrategySurrogate.yml","Akka.Actor.Failures":"Akka.Actor.Failures.yml","Akka.Actor.Failures.#ctor":"Akka.Actor.Failures.yml","Akka.Actor.Failures.Entries":"Akka.Actor.Failures.yml","Akka.Actor.Failure":"Akka.Actor.Failure.yml","Akka.Actor.Failure.Exception":"Akka.Actor.Failure.yml","Akka.Actor.Failure.Timestamp":"Akka.Actor.Failure.yml","Akka.Actor.Directive":"Akka.Actor.Directive.yml","Akka.Actor.Directive.Resume":"Akka.Actor.Directive.yml","Akka.Actor.Directive.Restart":"Akka.Actor.Directive.yml","Akka.Actor.Directive.Escalate":"Akka.Actor.Directive.yml","Akka.Actor.Directive.Stop":"Akka.Actor.Directive.yml","Akka.Actor.DirectiveExtensions":"Akka.Actor.DirectiveExtensions.yml","Akka.Actor.DirectiveExtensions.When``1(Akka.Actor.Directive)":"Akka.Actor.DirectiveExtensions.yml","Akka.Actor.IDecider":"Akka.Actor.IDecider.yml","Akka.Actor.IDecider.Decide(System.Exception)":"Akka.Actor.IDecider.yml","Akka.Actor.Decider":"Akka.Actor.Decider.yml","Akka.Actor.Decider.From(Akka.Actor.Directive,System.Collections.Generic.KeyValuePair{System.Type,Akka.Actor.Directive}[])":"Akka.Actor.Decider.yml","Akka.Actor.Decider.From(Akka.Actor.Directive,System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{System.Type,Akka.Actor.Directive}})":"Akka.Actor.Decider.yml","Akka.Actor.Decider.From(System.Func{System.Exception,Akka.Actor.Directive})":"Akka.Actor.Decider.yml","Akka.Actor.LocalOnlyDecider":"Akka.Actor.LocalOnlyDecider.yml","Akka.Actor.LocalOnlyDecider.#ctor(System.Func{System.Exception,Akka.Actor.Directive})":"Akka.Actor.LocalOnlyDecider.yml","Akka.Actor.LocalOnlyDecider.Decide(System.Exception)":"Akka.Actor.LocalOnlyDecider.yml","Akka.Actor.DeployableDecider":"Akka.Actor.DeployableDecider.yml","Akka.Actor.DeployableDecider.#ctor":"Akka.Actor.DeployableDecider.yml","Akka.Actor.DeployableDecider.#ctor(Akka.Actor.Directive,System.Collections.Generic.IEnumerable{System.Collections.Generic.KeyValuePair{System.Type,Akka.Actor.Directive}})":"Akka.Actor.DeployableDecider.yml","Akka.Actor.DeployableDecider.#ctor(Akka.Actor.Directive,System.Collections.Generic.KeyValuePair{System.Type,Akka.Actor.Directive}[])":"Akka.Actor.DeployableDecider.yml","Akka.Actor.DeployableDecider.DefaultDirective":"Akka.Actor.DeployableDecider.yml","Akka.Actor.DeployableDecider.Pairs":"Akka.Actor.DeployableDecider.yml","Akka.Actor.DeployableDecider.Decide(System.Exception)":"Akka.Actor.DeployableDecider.yml","Akka.Actor.DeployableDecider.Equals(Akka.Actor.DeployableDecider)":"Akka.Actor.DeployableDecider.yml","Akka.Actor.DeployableDecider.Equals(System.Object)":"Akka.Actor.DeployableDecider.yml","Akka.Actor.DeployableDecider.GetHashCode":"Akka.Actor.DeployableDecider.yml","Akka.Actor.SupervisorStrategyConfigurator":"Akka.Actor.SupervisorStrategyConfigurator.yml","Akka.Actor.SupervisorStrategyConfigurator.Create":"Akka.Actor.SupervisorStrategyConfigurator.yml","Akka.Actor.SupervisorStrategyConfigurator.CreateConfigurator(System.String)":"Akka.Actor.SupervisorStrategyConfigurator.yml","Akka.Actor.DefaultSupervisorStrategy":"Akka.Actor.DefaultSupervisorStrategy.yml","Akka.Actor.DefaultSupervisorStrategy.Create":"Akka.Actor.DefaultSupervisorStrategy.yml","Akka.Actor.StoppingSupervisorStrategy":"Akka.Actor.StoppingSupervisorStrategy.yml","Akka.Actor.StoppingSupervisorStrategy.Create":"Akka.Actor.StoppingSupervisorStrategy.yml","Akka.Actor.UntypedActor":"Akka.Actor.UntypedActor.yml","Akka.Actor.UntypedActor.Receive(System.Object)":"Akka.Actor.UntypedActor.yml","Akka.Actor.UntypedActor.RunTask(System.Action)":"Akka.Actor.UntypedActor.yml","Akka.Actor.UntypedActor.RunTask(System.Func{System.Threading.Tasks.Task})":"Akka.Actor.UntypedActor.yml","Akka.Actor.UntypedActor.OnReceive(System.Object)":"Akka.Actor.UntypedActor.yml","Akka.Actor.UntypedActor.Become(Akka.Actor.UntypedReceive,System.Boolean)":"Akka.Actor.UntypedActor.yml","Akka.Actor.UntypedActor.Become(Akka.Actor.UntypedReceive)":"Akka.Actor.UntypedActor.yml","Akka.Actor.UntypedActor.BecomeStacked(Akka.Actor.UntypedReceive)":"Akka.Actor.UntypedActor.yml","Akka.Actor.UntypedActor.Context":"Akka.Actor.UntypedActor.yml","Akka.Actor.LocalActorRef":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.#ctor(Akka.Actor.Internal.ActorSystemImpl,Akka.Actor.Props,Akka.Dispatch.MessageDispatcher,Akka.Dispatch.MailboxType,Akka.Actor.IInternalActorRef,Akka.Actor.ActorPath)":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.NewActorCell(Akka.Actor.Internal.ActorSystemImpl,Akka.Actor.IInternalActorRef,Akka.Actor.Props,Akka.Dispatch.MessageDispatcher,Akka.Actor.IInternalActorRef)":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Underlying":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Cell":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Provider":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Parent":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Children":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Start":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Stop":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Suspend":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.IsLocal":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.SendSystemMessage(Akka.Dispatch.SysMsg.ISystemMessage)":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Path":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.System":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Props":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Dispatcher":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Supervisor":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.IsTerminated":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.MailboxType":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Resume(System.Exception)":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.Restart(System.Exception)":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.TellInternal(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.GetSingleChild(System.String)":"Akka.Actor.LocalActorRef.yml","Akka.Actor.LocalActorRef.GetChild(System.Collections.Generic.IEnumerable{System.String})":"Akka.Actor.LocalActorRef.yml","Akka.Actor.Envelope":"Akka.Actor.Envelope.yml","Akka.Actor.Envelope.#ctor(System.Object,Akka.Actor.IActorRef,Akka.Actor.ActorSystem)":"Akka.Actor.Envelope.yml","Akka.Actor.Envelope.#ctor(System.Object,Akka.Actor.IActorRef)":"Akka.Actor.Envelope.yml","Akka.Actor.Envelope.Sender":"Akka.Actor.Envelope.yml","Akka.Actor.Envelope.Message":"Akka.Actor.Envelope.yml","Akka.Actor.Envelope.ToString":"Akka.Actor.Envelope.yml","Akka.Actor.UntypedReceive":"Akka.Actor.UntypedReceive.yml","Akka.Actor.IHandle`1":"Akka.Actor.IHandle-1.yml","Akka.Actor.IHandle`1.Handle(`0)":"Akka.Actor.IHandle-1.yml","Akka.Actor.TypedActor":"Akka.Actor.TypedActor.yml","Akka.Actor.TypedActor.Receive(System.Object)":"Akka.Actor.TypedActor.yml","Akka.Actor.INotInfluenceReceiveTimeout":"Akka.Actor.INotInfluenceReceiveTimeout.yml","Akka.Actor.Internal":"Akka.Actor.Internal.yml","Akka.Actor.Internal.IChildrenContainer":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.IChildrenContainer.Add(System.String,Akka.Actor.Internal.ChildRestartStats)":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.IChildrenContainer.Remove(Akka.Actor.IActorRef)":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.IChildrenContainer.TryGetByName(System.String,Akka.Actor.Internal.IChildStats@)":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.IChildrenContainer.TryGetByRef(Akka.Actor.IActorRef,Akka.Actor.Internal.ChildRestartStats@)":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.IChildrenContainer.Children":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.IChildrenContainer.Stats":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.IChildrenContainer.ShallDie(Akka.Actor.IActorRef)":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.IChildrenContainer.Reserve(System.String)":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.IChildrenContainer.Unreserve(System.String)":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.IChildrenContainer.IsTerminating":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.IChildrenContainer.IsNormal":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.IChildrenContainer.Contains(Akka.Actor.IActorRef)":"Akka.Actor.Internal.IChildrenContainer.yml","Akka.Actor.Internal.ChildrenContainerBase":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.#ctor(System.Collections.Immutable.IImmutableDictionary{System.String,Akka.Actor.Internal.IChildStats})":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.IsTerminating":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.IsNormal":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.Add(System.String,Akka.Actor.Internal.ChildRestartStats)":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.Remove(Akka.Actor.IActorRef)":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.Reserve(System.String)":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.ShallDie(Akka.Actor.IActorRef)":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.Unreserve(System.String)":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.Children":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.Stats":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.InternalChildren":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.TryGetByName(System.String,Akka.Actor.Internal.IChildStats@)":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.TryGetByRef(Akka.Actor.IActorRef,Akka.Actor.Internal.ChildRestartStats@)":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.Contains(Akka.Actor.IActorRef)":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.ChildrenContainerBase.ChildStatsAppender(System.Text.StringBuilder,System.Collections.Generic.KeyValuePair{System.String,Akka.Actor.Internal.IChildStats},System.Int32)":"Akka.Actor.Internal.ChildrenContainerBase.yml","Akka.Actor.Internal.IChildStats":"Akka.Actor.Internal.IChildStats.yml","Akka.Actor.Internal.ChildNameReserved":"Akka.Actor.Internal.ChildNameReserved.yml","Akka.Actor.Internal.ChildNameReserved.Instance":"Akka.Actor.Internal.ChildNameReserved.yml","Akka.Actor.Internal.ChildNameReserved.ToString":"Akka.Actor.Internal.ChildNameReserved.yml","Akka.Actor.Internal.ChildRestartStats":"Akka.Actor.Internal.ChildRestartStats.yml","Akka.Actor.Internal.ChildRestartStats.#ctor(Akka.Actor.IInternalActorRef,System.UInt32,System.Int64)":"Akka.Actor.Internal.ChildRestartStats.yml","Akka.Actor.Internal.ChildRestartStats.Uid":"Akka.Actor.Internal.ChildRestartStats.yml","Akka.Actor.Internal.ChildRestartStats.Child":"Akka.Actor.Internal.ChildRestartStats.yml","Akka.Actor.Internal.ChildRestartStats.MaxNrOfRetriesCount":"Akka.Actor.Internal.ChildRestartStats.yml","Akka.Actor.Internal.ChildRestartStats.RestartTimeWindowStartTicks":"Akka.Actor.Internal.ChildRestartStats.yml","Akka.Actor.Internal.ChildRestartStats.RequestRestartPermission(System.Int32,System.Int32)":"Akka.Actor.Internal.ChildRestartStats.yml","Akka.Actor.Internal.EmptyChildrenContainer":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.#ctor":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.Instance":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.Add(System.String,Akka.Actor.Internal.ChildRestartStats)":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.Remove(Akka.Actor.IActorRef)":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.TryGetByName(System.String,Akka.Actor.Internal.IChildStats@)":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.TryGetByRef(Akka.Actor.IActorRef,Akka.Actor.Internal.ChildRestartStats@)":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.Contains(Akka.Actor.IActorRef)":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.Children":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.Stats":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.ShallDie(Akka.Actor.IActorRef)":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.Reserve(System.String)":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.Unreserve(System.String)":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.ToString":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.IsTerminating":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.EmptyChildrenContainer.IsNormal":"Akka.Actor.Internal.EmptyChildrenContainer.yml","Akka.Actor.Internal.NormalChildrenContainer":"Akka.Actor.Internal.NormalChildrenContainer.yml","Akka.Actor.Internal.NormalChildrenContainer.Create(System.Collections.Immutable.IImmutableDictionary{System.String,Akka.Actor.Internal.IChildStats})":"Akka.Actor.Internal.NormalChildrenContainer.yml","Akka.Actor.Internal.NormalChildrenContainer.Add(System.String,Akka.Actor.Internal.ChildRestartStats)":"Akka.Actor.Internal.NormalChildrenContainer.yml","Akka.Actor.Internal.NormalChildrenContainer.Remove(Akka.Actor.IActorRef)":"Akka.Actor.Internal.NormalChildrenContainer.yml","Akka.Actor.Internal.NormalChildrenContainer.ShallDie(Akka.Actor.IActorRef)":"Akka.Actor.Internal.NormalChildrenContainer.yml","Akka.Actor.Internal.NormalChildrenContainer.Reserve(System.String)":"Akka.Actor.Internal.NormalChildrenContainer.yml","Akka.Actor.Internal.NormalChildrenContainer.Unreserve(System.String)":"Akka.Actor.Internal.NormalChildrenContainer.yml","Akka.Actor.Internal.NormalChildrenContainer.ToString":"Akka.Actor.Internal.NormalChildrenContainer.yml","Akka.Actor.Internal.SuspendReason":"Akka.Actor.Internal.SuspendReason.yml","Akka.Actor.Internal.SuspendReason.IWaitingForChildren":"Akka.Actor.Internal.SuspendReason.IWaitingForChildren.yml","Akka.Actor.Internal.SuspendReason.Creation":"Akka.Actor.Internal.SuspendReason.Creation.yml","Akka.Actor.Internal.SuspendReason.Recreation":"Akka.Actor.Internal.SuspendReason.Recreation.yml","Akka.Actor.Internal.SuspendReason.Recreation.#ctor(System.Exception)":"Akka.Actor.Internal.SuspendReason.Recreation.yml","Akka.Actor.Internal.SuspendReason.Recreation.Cause":"Akka.Actor.Internal.SuspendReason.Recreation.yml","Akka.Actor.Internal.SuspendReason.Termination":"Akka.Actor.Internal.SuspendReason.Termination.yml","Akka.Actor.Internal.SuspendReason.Termination.Instance":"Akka.Actor.Internal.SuspendReason.Termination.yml","Akka.Actor.Internal.SuspendReason.UserRequest":"Akka.Actor.Internal.SuspendReason.UserRequest.yml","Akka.Actor.Internal.SuspendReason.UserRequest.Instance":"Akka.Actor.Internal.SuspendReason.UserRequest.yml","Akka.Actor.Internal.TerminatedChildrenContainer":"Akka.Actor.Internal.TerminatedChildrenContainer.yml","Akka.Actor.Internal.TerminatedChildrenContainer.Instance":"Akka.Actor.Internal.TerminatedChildrenContainer.yml","Akka.Actor.Internal.TerminatedChildrenContainer.Add(System.String,Akka.Actor.Internal.ChildRestartStats)":"Akka.Actor.Internal.TerminatedChildrenContainer.yml","Akka.Actor.Internal.TerminatedChildrenContainer.Reserve(System.String)":"Akka.Actor.Internal.TerminatedChildrenContainer.yml","Akka.Actor.Internal.TerminatedChildrenContainer.IsTerminating":"Akka.Actor.Internal.TerminatedChildrenContainer.yml","Akka.Actor.Internal.TerminatedChildrenContainer.IsNormal":"Akka.Actor.Internal.TerminatedChildrenContainer.yml","Akka.Actor.Internal.TerminatedChildrenContainer.ToString":"Akka.Actor.Internal.TerminatedChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer.#ctor(System.Collections.Immutable.IImmutableDictionary{System.String,Akka.Actor.Internal.IChildStats},Akka.Actor.IActorRef,Akka.Actor.Internal.SuspendReason)":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer.#ctor(System.Collections.Immutable.IImmutableDictionary{System.String,Akka.Actor.Internal.IChildStats},System.Collections.Immutable.ImmutableHashSet{Akka.Actor.IActorRef},Akka.Actor.Internal.SuspendReason)":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer.Reason":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer.Add(System.String,Akka.Actor.Internal.ChildRestartStats)":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer.Remove(Akka.Actor.IActorRef)":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer.ShallDie(Akka.Actor.IActorRef)":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer.Reserve(System.String)":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer.Unreserve(System.String)":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer.IsTerminating":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer.IsNormal":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer.ToString":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.TerminatingChildrenContainer.CreateCopyWithReason(Akka.Actor.Internal.SuspendReason)":"Akka.Actor.Internal.TerminatingChildrenContainer.yml","Akka.Actor.Internal.InternalCurrentActorCellKeeper":"Akka.Actor.Internal.InternalCurrentActorCellKeeper.yml","Akka.Actor.Internal.InternalCurrentActorCellKeeper.Current":"Akka.Actor.Internal.InternalCurrentActorCellKeeper.yml","Akka.Actor.Internal.IInternalSupportsTestFSMRef`2":"Akka.Actor.Internal.IInternalSupportsTestFSMRef-2.yml","Akka.Actor.Internal.IInternalSupportsTestFSMRef`2.ApplyState(Akka.Actor.FSMBase.State{`0,`1})":"Akka.Actor.Internal.IInternalSupportsTestFSMRef-2.yml","Akka.Actor.Internal.IInternalSupportsTestFSMRef`2.IsStateTimerActive":"Akka.Actor.Internal.IInternalSupportsTestFSMRef-2.yml","Akka.Actor.Internal.InternalActivateFsmLogging":"Akka.Actor.Internal.InternalActivateFsmLogging.yml","Akka.Actor.Internal.InternalActivateFsmLogging.Instance":"Akka.Actor.Internal.InternalActivateFsmLogging.yml","Akka.Actor.Internal.IInitializableActor":"Akka.Actor.Internal.IInitializableActor.yml","Akka.Actor.Internal.IInitializableActor.Init":"Akka.Actor.Internal.IInitializableActor.yml","Akka.Actor.Internal.ActorSystemImpl":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.#ctor(System.String)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.#ctor(System.String,Akka.Configuration.Config)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Provider":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Settings":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Name":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Serialization":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.EventStream":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.DeadLetters":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Dispatchers":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Mailboxes":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Scheduler":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Log":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.ActorPipelineResolver":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Guardian":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.LookupRoot":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.SystemGuardian":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.SystemActorOf(Akka.Actor.Props,System.String)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.SystemActorOf``1(System.String)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Abort":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Start":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.ActorOf(Akka.Actor.Props,System.String)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.ActorSelection(Akka.Actor.ActorPath)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.ActorSelection(System.String)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.RegisterExtension(Akka.Actor.IExtensionId)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.GetExtension(Akka.Actor.IExtensionId)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.TryGetExtension(System.Type,System.Object@)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.TryGetExtension``1(``0@)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.GetExtension``1":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.HasExtension(System.Type)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.HasExtension``1":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.RegisterOnTermination(System.Action)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Shutdown":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Terminate":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.TerminationTask":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.AwaitTermination":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.AwaitTermination(System.TimeSpan)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.AwaitTermination(System.TimeSpan,System.Threading.CancellationToken)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.WhenTerminated":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.ActorSystemImpl.Stop(Akka.Actor.IActorRef)":"Akka.Actor.Internal.ActorSystemImpl.yml","Akka.Actor.Internal.AbstractStash":"Akka.Actor.Internal.AbstractStash.yml","Akka.Actor.Internal.AbstractStash.#ctor(Akka.Actor.IActorContext,System.Int32)":"Akka.Actor.Internal.AbstractStash.yml","Akka.Actor.Internal.AbstractStash.Stash":"Akka.Actor.Internal.AbstractStash.yml","Akka.Actor.Internal.AbstractStash.Unstash":"Akka.Actor.Internal.AbstractStash.yml","Akka.Actor.Internal.AbstractStash.UnstashAll":"Akka.Actor.Internal.AbstractStash.yml","Akka.Actor.Internal.AbstractStash.UnstashAll(System.Func{Akka.Actor.Envelope,System.Boolean})":"Akka.Actor.Internal.AbstractStash.yml","Akka.Actor.Internal.AbstractStash.ClearStash":"Akka.Actor.Internal.AbstractStash.yml","Akka.Actor.Internal.AbstractStash.Prepend(System.Collections.Generic.IEnumerable{Akka.Actor.Envelope})":"Akka.Actor.Internal.AbstractStash.yml","Akka.Actor.Internal.BoundedStashImpl":"Akka.Actor.Internal.BoundedStashImpl.yml","Akka.Actor.Internal.BoundedStashImpl.#ctor(Akka.Actor.IActorContext,System.Int32)":"Akka.Actor.Internal.BoundedStashImpl.yml","Akka.Actor.Internal.UnboundedStashImpl":"Akka.Actor.Internal.UnboundedStashImpl.yml","Akka.Actor.Internal.UnboundedStashImpl.#ctor(Akka.Actor.IActorContext)":"Akka.Actor.Internal.UnboundedStashImpl.yml","Akka.Actor.Dsl":"Akka.Actor.Dsl.yml","Akka.Actor.Dsl.IActorDsl":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.OnPostRestart":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.OnPreRestart":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.OnPostStop":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.OnPreStart":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.Strategy":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.Receive``1(System.Action{``0,Akka.Actor.IActorContext})":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.Receive``1(System.Predicate{``0},System.Action{``0,Akka.Actor.IActorContext})":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.Receive``1(System.Action{``0,Akka.Actor.IActorContext},System.Predicate{``0})":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.ReceiveAny(System.Action{System.Object,Akka.Actor.IActorContext})":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.ReceiveAsync``1(System.Func{``0,Akka.Actor.IActorContext,System.Threading.Tasks.Task},System.Predicate{``0})":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.ReceiveAsync``1(System.Predicate{``0},System.Func{``0,Akka.Actor.IActorContext,System.Threading.Tasks.Task})":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.ReceiveAnyAsync(System.Func{System.Object,Akka.Actor.IActorContext,System.Threading.Tasks.Task})":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.DefaultPreRestart(System.Exception,System.Object)":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.DefaultPostRestart(System.Exception)":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.DefaultPreStart":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.DefaultPostStop":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.Become(System.Action{System.Object,Akka.Actor.IActorContext})":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.BecomeStacked(System.Action{System.Object,Akka.Actor.IActorContext})":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.UnbecomeStacked":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.IActorDsl.ActorOf(System.Action{Akka.Actor.Dsl.IActorDsl},System.String)":"Akka.Actor.Dsl.IActorDsl.yml","Akka.Actor.Dsl.Act":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.OnPostRestart":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.OnPreRestart":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.OnPostStop":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.OnPreStart":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.Strategy":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.#ctor(System.Action{Akka.Actor.Dsl.IActorDsl})":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.#ctor(System.Action{Akka.Actor.Dsl.IActorDsl,Akka.Actor.IActorContext})":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.Receive``1(System.Action{``0,Akka.Actor.IActorContext})":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.Receive``1(System.Action{``0,Akka.Actor.IActorContext},System.Predicate{``0})":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.Receive``1(System.Predicate{``0},System.Action{``0,Akka.Actor.IActorContext})":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.ReceiveAny(System.Action{System.Object,Akka.Actor.IActorContext})":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.ReceiveAsync``1(System.Func{``0,Akka.Actor.IActorContext,System.Threading.Tasks.Task},System.Predicate{``0})":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.ReceiveAsync``1(System.Predicate{``0},System.Func{``0,Akka.Actor.IActorContext,System.Threading.Tasks.Task})":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.ReceiveAnyAsync(System.Func{System.Object,Akka.Actor.IActorContext,System.Threading.Tasks.Task})":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.DefaultPreRestart(System.Exception,System.Object)":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.DefaultPostRestart(System.Exception)":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.DefaultPreStart":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.DefaultPostStop":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.Become(System.Action{System.Object,Akka.Actor.IActorContext})":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.BecomeStacked(System.Action{System.Object,Akka.Actor.IActorContext})":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.Akka#Actor#Dsl#IActorDsl#UnbecomeStacked":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.ActorOf(System.Action{Akka.Actor.Dsl.IActorDsl},System.String)":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.PreRestart(System.Exception,System.Object)":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.PostRestart(System.Exception)":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.PostStop":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.PreStart":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.Act.SupervisorStrategy":"Akka.Actor.Dsl.Act.yml","Akka.Actor.Dsl.ActExtensions":"Akka.Actor.Dsl.ActExtensions.yml","Akka.Actor.Dsl.ActExtensions.ActorOf(Akka.Actor.IActorRefFactory,System.Action{Akka.Actor.Dsl.IActorDsl},System.String)":"Akka.Actor.Dsl.ActExtensions.yml","Akka.Actor.Dsl.ActExtensions.ActorOf(Akka.Actor.IActorRefFactory,System.Action{Akka.Actor.Dsl.IActorDsl,Akka.Actor.IActorContext},System.String)":"Akka.Actor.Dsl.ActExtensions.yml","Akka.Configuration":"Akka.Configuration.yml","Akka.Configuration.ConfigurationException":"Akka.Configuration.ConfigurationException.yml","Akka.Configuration.ConfigurationException.#ctor(System.String)":"Akka.Configuration.ConfigurationException.yml","Akka.Configuration.ConfigurationException.#ctor(System.String,System.Exception)":"Akka.Configuration.ConfigurationException.yml","Akka.Configuration.ConfigurationException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Configuration.ConfigurationException.yml","Akka.Configuration.ConfigurationFactory":"Akka.Configuration.ConfigurationFactory.yml","Akka.Configuration.ConfigurationFactory.Empty":"Akka.Configuration.ConfigurationFactory.yml","Akka.Configuration.ConfigurationFactory.ParseString(System.String,System.Func{System.String,Akka.Configuration.Hocon.HoconRoot})":"Akka.Configuration.ConfigurationFactory.yml","Akka.Configuration.ConfigurationFactory.ParseString(System.String)":"Akka.Configuration.ConfigurationFactory.yml","Akka.Configuration.ConfigurationFactory.Load":"Akka.Configuration.ConfigurationFactory.yml","Akka.Configuration.ConfigurationFactory.Default":"Akka.Configuration.ConfigurationFactory.yml","Akka.Configuration.ConfigurationFactory.FromResource(System.String,System.Object)":"Akka.Configuration.ConfigurationFactory.yml","Akka.Configuration.ConfigurationFactory.FromResource``1(System.String)":"Akka.Configuration.ConfigurationFactory.yml","Akka.Configuration.ConfigurationFactory.FromResource(System.String,System.Reflection.Assembly)":"Akka.Configuration.ConfigurationFactory.yml","Akka.Configuration.ConfigurationFactory.FromObject(System.Object)":"Akka.Configuration.ConfigurationFactory.yml","Akka.Configuration.Config":"Akka.Configuration.Config.yml","Akka.Configuration.Config.#ctor":"Akka.Configuration.Config.yml","Akka.Configuration.Config.#ctor(Akka.Configuration.Hocon.HoconRoot)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.#ctor(Akka.Configuration.Config,Akka.Configuration.Config)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.Fallback":"Akka.Configuration.Config.yml","Akka.Configuration.Config.IsEmpty":"Akka.Configuration.Config.yml","Akka.Configuration.Config.Root":"Akka.Configuration.Config.yml","Akka.Configuration.Config.Substitutions":"Akka.Configuration.Config.yml","Akka.Configuration.Config.Copy(Akka.Configuration.Config)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetBoolean(System.String,System.Boolean)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetByteSize(System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetInt(System.String,System.Int32)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetLong(System.String,System.Int64)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetString(System.String,System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetFloat(System.String,System.Single)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetDecimal(System.String,System.Decimal)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetDouble(System.String,System.Double)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetBooleanList(System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetDecimalList(System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetFloatList(System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetDoubleList(System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetIntList(System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetLongList(System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetByteList(System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetStringList(System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetConfig(System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetValue(System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetMillisDuration(System.String,System.Nullable{System.TimeSpan},System.Boolean)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.GetTimeSpan(System.String,System.Nullable{System.TimeSpan},System.Boolean)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.ToString":"Akka.Configuration.Config.yml","Akka.Configuration.Config.ToString(System.Boolean)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.WithFallback(Akka.Configuration.Config)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.HasPath(System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.op_Addition(Akka.Configuration.Config,System.String)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.op_Addition(System.String,Akka.Configuration.Config)":"Akka.Configuration.Config.yml","Akka.Configuration.Config.op_Implicit(System.String)~Akka.Configuration.Config":"Akka.Configuration.Config.yml","Akka.Configuration.Config.AsEnumerable":"Akka.Configuration.Config.yml","Akka.Configuration.Config.Empty":"Akka.Configuration.Config.yml","Akka.Configuration.ConfigExtensions":"Akka.Configuration.ConfigExtensions.yml","Akka.Configuration.ConfigExtensions.SafeWithFallback(Akka.Configuration.Config,Akka.Configuration.Config)":"Akka.Configuration.ConfigExtensions.yml","Akka.Configuration.ConfigExtensions.IsNullOrEmpty(Akka.Configuration.Config)":"Akka.Configuration.ConfigExtensions.yml","Akka.Configuration.Hocon":"Akka.Configuration.Hocon.yml","Akka.Configuration.Hocon.AkkaConfigurationSection":"Akka.Configuration.Hocon.AkkaConfigurationSection.yml","Akka.Configuration.Hocon.AkkaConfigurationSection.AkkaConfig":"Akka.Configuration.Hocon.AkkaConfigurationSection.yml","Akka.Configuration.Hocon.AkkaConfigurationSection.Hocon":"Akka.Configuration.Hocon.AkkaConfigurationSection.yml","Akka.Configuration.Hocon.CDataConfigurationElement":"Akka.Configuration.Hocon.CDataConfigurationElement.yml","Akka.Configuration.Hocon.CDataConfigurationElement.ContentPropertyName":"Akka.Configuration.Hocon.CDataConfigurationElement.yml","Akka.Configuration.Hocon.CDataConfigurationElement.DeserializeElement(System.Xml.XmlReader,System.Boolean)":"Akka.Configuration.Hocon.CDataConfigurationElement.yml","Akka.Configuration.Hocon.HoconArray":"Akka.Configuration.Hocon.HoconArray.yml","Akka.Configuration.Hocon.HoconArray.IsString":"Akka.Configuration.Hocon.HoconArray.yml","Akka.Configuration.Hocon.HoconArray.GetString":"Akka.Configuration.Hocon.HoconArray.yml","Akka.Configuration.Hocon.HoconArray.IsArray":"Akka.Configuration.Hocon.HoconArray.yml","Akka.Configuration.Hocon.HoconArray.GetArray":"Akka.Configuration.Hocon.HoconArray.yml","Akka.Configuration.Hocon.HoconArray.ToString":"Akka.Configuration.Hocon.HoconArray.yml","Akka.Configuration.Hocon.HoconConfigurationElement":"Akka.Configuration.Hocon.HoconConfigurationElement.yml","Akka.Configuration.Hocon.HoconConfigurationElement.Content":"Akka.Configuration.Hocon.HoconConfigurationElement.yml","Akka.Configuration.Hocon.HoconLiteral":"Akka.Configuration.Hocon.HoconLiteral.yml","Akka.Configuration.Hocon.HoconLiteral.Value":"Akka.Configuration.Hocon.HoconLiteral.yml","Akka.Configuration.Hocon.HoconLiteral.IsString":"Akka.Configuration.Hocon.HoconLiteral.yml","Akka.Configuration.Hocon.HoconLiteral.GetString":"Akka.Configuration.Hocon.HoconLiteral.yml","Akka.Configuration.Hocon.HoconLiteral.IsArray":"Akka.Configuration.Hocon.HoconLiteral.yml","Akka.Configuration.Hocon.HoconLiteral.GetArray":"Akka.Configuration.Hocon.HoconLiteral.yml","Akka.Configuration.Hocon.HoconLiteral.ToString":"Akka.Configuration.Hocon.HoconLiteral.yml","Akka.Configuration.Hocon.HoconObject":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.HoconObject.#ctor":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.HoconObject.Unwrapped":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.HoconObject.Items":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.HoconObject.IsString":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.HoconObject.GetString":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.HoconObject.IsArray":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.HoconObject.GetArray":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.HoconObject.GetKey(System.String)":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.HoconObject.GetOrCreateKey(System.String)":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.HoconObject.ToString":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.HoconObject.ToString(System.Int32)":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.HoconObject.Merge(Akka.Configuration.Hocon.HoconObject)":"Akka.Configuration.Hocon.HoconObject.yml","Akka.Configuration.Hocon.Parser":"Akka.Configuration.Hocon.Parser.yml","Akka.Configuration.Hocon.Parser.Parse(System.String,System.Func{System.String,Akka.Configuration.Hocon.HoconRoot})":"Akka.Configuration.Hocon.Parser.yml","Akka.Configuration.Hocon.Parser.ParseValue(Akka.Configuration.Hocon.HoconValue,System.String)":"Akka.Configuration.Hocon.Parser.yml","Akka.Configuration.Hocon.Parser.ParseArray(System.String)":"Akka.Configuration.Hocon.Parser.yml","Akka.Configuration.Hocon.HoconRoot":"Akka.Configuration.Hocon.HoconRoot.yml","Akka.Configuration.Hocon.HoconRoot.#ctor":"Akka.Configuration.Hocon.HoconRoot.yml","Akka.Configuration.Hocon.HoconRoot.#ctor(Akka.Configuration.Hocon.HoconValue,System.Collections.Generic.IEnumerable{Akka.Configuration.Hocon.HoconSubstitution})":"Akka.Configuration.Hocon.HoconRoot.yml","Akka.Configuration.Hocon.HoconRoot.#ctor(Akka.Configuration.Hocon.HoconValue)":"Akka.Configuration.Hocon.HoconRoot.yml","Akka.Configuration.Hocon.HoconRoot.Value":"Akka.Configuration.Hocon.HoconRoot.yml","Akka.Configuration.Hocon.HoconRoot.Substitutions":"Akka.Configuration.Hocon.HoconRoot.yml","Akka.Configuration.Hocon.HoconSubstitution":"Akka.Configuration.Hocon.HoconSubstitution.yml","Akka.Configuration.Hocon.HoconSubstitution.#ctor":"Akka.Configuration.Hocon.HoconSubstitution.yml","Akka.Configuration.Hocon.HoconSubstitution.#ctor(System.String)":"Akka.Configuration.Hocon.HoconSubstitution.yml","Akka.Configuration.Hocon.HoconSubstitution.Path":"Akka.Configuration.Hocon.HoconSubstitution.yml","Akka.Configuration.Hocon.HoconSubstitution.ResolvedValue":"Akka.Configuration.Hocon.HoconSubstitution.yml","Akka.Configuration.Hocon.HoconSubstitution.IsString":"Akka.Configuration.Hocon.HoconSubstitution.yml","Akka.Configuration.Hocon.HoconSubstitution.GetString":"Akka.Configuration.Hocon.HoconSubstitution.yml","Akka.Configuration.Hocon.HoconSubstitution.IsArray":"Akka.Configuration.Hocon.HoconSubstitution.yml","Akka.Configuration.Hocon.HoconSubstitution.GetArray":"Akka.Configuration.Hocon.HoconSubstitution.yml","Akka.Configuration.Hocon.HoconSubstitution.IsObject":"Akka.Configuration.Hocon.HoconSubstitution.yml","Akka.Configuration.Hocon.HoconSubstitution.GetObject":"Akka.Configuration.Hocon.HoconSubstitution.yml","Akka.Configuration.Hocon.TokenType":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.Comment":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.Key":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.LiteralValue":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.Assign":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.ObjectStart":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.ObjectEnd":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.Dot":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.EoF":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.ArrayStart":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.ArrayEnd":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.Comma":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.Substitute":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.TokenType.Include":"Akka.Configuration.Hocon.TokenType.yml","Akka.Configuration.Hocon.Token":"Akka.Configuration.Hocon.Token.yml","Akka.Configuration.Hocon.Token.#ctor":"Akka.Configuration.Hocon.Token.yml","Akka.Configuration.Hocon.Token.#ctor(Akka.Configuration.Hocon.TokenType)":"Akka.Configuration.Hocon.Token.yml","Akka.Configuration.Hocon.Token.#ctor(System.String)":"Akka.Configuration.Hocon.Token.yml","Akka.Configuration.Hocon.Token.Value":"Akka.Configuration.Hocon.Token.yml","Akka.Configuration.Hocon.Token.Type":"Akka.Configuration.Hocon.Token.yml","Akka.Configuration.Hocon.Token.Key(System.String)":"Akka.Configuration.Hocon.Token.yml","Akka.Configuration.Hocon.Token.Substitution(System.String)":"Akka.Configuration.Hocon.Token.yml","Akka.Configuration.Hocon.Token.LiteralValue(System.String)":"Akka.Configuration.Hocon.Token.yml","Akka.Configuration.Hocon.Tokenizer":"Akka.Configuration.Hocon.Tokenizer.yml","Akka.Configuration.Hocon.Tokenizer.Push":"Akka.Configuration.Hocon.Tokenizer.yml","Akka.Configuration.Hocon.Tokenizer.Pop":"Akka.Configuration.Hocon.Tokenizer.yml","Akka.Configuration.Hocon.Tokenizer.#ctor(System.String)":"Akka.Configuration.Hocon.Tokenizer.yml","Akka.Configuration.Hocon.Tokenizer.EoF":"Akka.Configuration.Hocon.Tokenizer.yml","Akka.Configuration.Hocon.Tokenizer.Matches(System.String)":"Akka.Configuration.Hocon.Tokenizer.yml","Akka.Configuration.Hocon.Tokenizer.Take(System.Int32)":"Akka.Configuration.Hocon.Tokenizer.yml","Akka.Configuration.Hocon.Tokenizer.Matches(System.String[])":"Akka.Configuration.Hocon.Tokenizer.yml","Akka.Configuration.Hocon.Tokenizer.Peek":"Akka.Configuration.Hocon.Tokenizer.yml","Akka.Configuration.Hocon.Tokenizer.Take":"Akka.Configuration.Hocon.Tokenizer.yml","Akka.Configuration.Hocon.Tokenizer.PullWhitespace":"Akka.Configuration.Hocon.Tokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.#ctor(System.String)":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullWhitespaceAndComments":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullRestOfLine":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullNext":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullArrayEnd":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsArrayEnd":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsArrayStart":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullArrayStart":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullDot":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullComma":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullStartOfObject":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullEndOfObject":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullAssignment":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsComma":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsDot":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsObjectStart":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsEndOfObject":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsAssignment":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsStartOfQuotedText":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsStartOfTripleQuotedText":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullComment":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullUnquotedKey":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsUnquotedKey":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsUnquotedKeyStart":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsWhitespace":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsWhitespaceOrComment":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullTripleQuotedText":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullQuotedText":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullQuotedKey":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullInclude":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsStartOfComment":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullValue":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsSubstitutionStart":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsInclude":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullSubstitution":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsSpaceOrTab":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.IsStartSimpleValue":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullSpaceOrTab":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconTokenizer.PullSimpleValue":"Akka.Configuration.Hocon.HoconTokenizer.yml","Akka.Configuration.Hocon.HoconValue":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.#ctor":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.#ctor(System.Collections.Generic.List{Akka.Configuration.Hocon.IHoconElement},System.Boolean)":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.IsEmpty":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.Values":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.AtKey(System.String)":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetObject":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.IsObject":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.AppendValue(Akka.Configuration.Hocon.IHoconElement)":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.Clear":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.NewValue(Akka.Configuration.Hocon.IHoconElement)":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.IsString":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetChildObject(System.String)":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetBoolean":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetString":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetDecimal":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetFloat":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetDouble":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetLong":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetInt":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetByte":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetByteList":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetIntList":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetLongList":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetBooleanList":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetFloatList":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetDoubleList":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetDecimalList":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetStringList":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetArray":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.IsArray":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetMillisDuration(System.Boolean)":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetTimeSpan(System.Boolean)":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.GetByteSize":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.ToString":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.HoconValue.ToString(System.Int32)":"Akka.Configuration.Hocon.HoconValue.yml","Akka.Configuration.Hocon.IMightBeAHoconObject":"Akka.Configuration.Hocon.IMightBeAHoconObject.yml","Akka.Configuration.Hocon.IMightBeAHoconObject.IsObject":"Akka.Configuration.Hocon.IMightBeAHoconObject.yml","Akka.Configuration.Hocon.IMightBeAHoconObject.GetObject":"Akka.Configuration.Hocon.IMightBeAHoconObject.yml","Akka.Configuration.Hocon.IHoconElement":"Akka.Configuration.Hocon.IHoconElement.yml","Akka.Configuration.Hocon.IHoconElement.IsString":"Akka.Configuration.Hocon.IHoconElement.yml","Akka.Configuration.Hocon.IHoconElement.GetString":"Akka.Configuration.Hocon.IHoconElement.yml","Akka.Configuration.Hocon.IHoconElement.IsArray":"Akka.Configuration.Hocon.IHoconElement.yml","Akka.Configuration.Hocon.IHoconElement.GetArray":"Akka.Configuration.Hocon.IHoconElement.yml","Akka.Dispatch":"Akka.Dispatch.yml","Akka.Dispatch.IDispatcherPrerequisites":"Akka.Dispatch.IDispatcherPrerequisites.yml","Akka.Dispatch.IDispatcherPrerequisites.EventStream":"Akka.Dispatch.IDispatcherPrerequisites.yml","Akka.Dispatch.IDispatcherPrerequisites.Scheduler":"Akka.Dispatch.IDispatcherPrerequisites.yml","Akka.Dispatch.IDispatcherPrerequisites.Settings":"Akka.Dispatch.IDispatcherPrerequisites.yml","Akka.Dispatch.IDispatcherPrerequisites.Mailboxes":"Akka.Dispatch.IDispatcherPrerequisites.yml","Akka.Dispatch.DefaultDispatcherPrerequisites":"Akka.Dispatch.DefaultDispatcherPrerequisites.yml","Akka.Dispatch.DefaultDispatcherPrerequisites.#ctor(Akka.Event.EventStream,Akka.Actor.IScheduler,Akka.Actor.Settings,Akka.Dispatch.Mailboxes)":"Akka.Dispatch.DefaultDispatcherPrerequisites.yml","Akka.Dispatch.DefaultDispatcherPrerequisites.EventStream":"Akka.Dispatch.DefaultDispatcherPrerequisites.yml","Akka.Dispatch.DefaultDispatcherPrerequisites.Scheduler":"Akka.Dispatch.DefaultDispatcherPrerequisites.yml","Akka.Dispatch.DefaultDispatcherPrerequisites.Settings":"Akka.Dispatch.DefaultDispatcherPrerequisites.yml","Akka.Dispatch.DefaultDispatcherPrerequisites.Mailboxes":"Akka.Dispatch.DefaultDispatcherPrerequisites.yml","Akka.Dispatch.ExecutorServiceConfigurator":"Akka.Dispatch.ExecutorServiceConfigurator.yml","Akka.Dispatch.ExecutorServiceConfigurator.#ctor(Akka.Configuration.Config,Akka.Dispatch.IDispatcherPrerequisites)":"Akka.Dispatch.ExecutorServiceConfigurator.yml","Akka.Dispatch.ExecutorServiceConfigurator.Config":"Akka.Dispatch.ExecutorServiceConfigurator.yml","Akka.Dispatch.ExecutorServiceConfigurator.Prerequisites":"Akka.Dispatch.ExecutorServiceConfigurator.yml","Akka.Dispatch.MessageDispatcherConfigurator":"Akka.Dispatch.MessageDispatcherConfigurator.yml","Akka.Dispatch.MessageDispatcherConfigurator.#ctor(Akka.Configuration.Config,Akka.Dispatch.IDispatcherPrerequisites)":"Akka.Dispatch.MessageDispatcherConfigurator.yml","Akka.Dispatch.MessageDispatcherConfigurator.Config":"Akka.Dispatch.MessageDispatcherConfigurator.yml","Akka.Dispatch.MessageDispatcherConfigurator.Prerequisites":"Akka.Dispatch.MessageDispatcherConfigurator.yml","Akka.Dispatch.MessageDispatcherConfigurator.Dispatcher":"Akka.Dispatch.MessageDispatcherConfigurator.yml","Akka.Dispatch.MessageDispatcherConfigurator.ConfigureExecutor":"Akka.Dispatch.MessageDispatcherConfigurator.yml","Akka.Dispatch.MessageDispatcher":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.DefaultThroughput":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.Configurator":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.#ctor(Akka.Dispatch.MessageDispatcherConfigurator)":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.EventStream":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.Mailboxes":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.Id":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.ThroughputDeadlineTime":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.Throughput":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.ShutdownTimeout":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.Inhabitants":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.Schedule(System.Action)":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.Schedule(Akka.Dispatch.IRunnable)":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.ExecuteTask(Akka.Dispatch.IRunnable)":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.ReportFailure(System.Exception)":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.Shutdown":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.Dispatch(Akka.Actor.ActorCell,Akka.Actor.Envelope)":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.SystemDispatch(Akka.Actor.ActorCell,Akka.Dispatch.SysMsg.SystemMessage)":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.Attach(Akka.Actor.ActorCell)":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.MessageDispatcher.Detach(Akka.Actor.ActorCell)":"Akka.Dispatch.MessageDispatcher.yml","Akka.Dispatch.ActorTaskScheduler":"Akka.Dispatch.ActorTaskScheduler.yml","Akka.Dispatch.ActorTaskScheduler.CurrentMessage":"Akka.Dispatch.ActorTaskScheduler.yml","Akka.Dispatch.ActorTaskScheduler.MaximumConcurrencyLevel":"Akka.Dispatch.ActorTaskScheduler.yml","Akka.Dispatch.ActorTaskScheduler.GetScheduledTasks":"Akka.Dispatch.ActorTaskScheduler.yml","Akka.Dispatch.ActorTaskScheduler.QueueTask(System.Threading.Tasks.Task)":"Akka.Dispatch.ActorTaskScheduler.yml","Akka.Dispatch.ActorTaskScheduler.TryExecuteTaskInline(System.Threading.Tasks.Task,System.Boolean)":"Akka.Dispatch.ActorTaskScheduler.yml","Akka.Dispatch.ActorTaskScheduler.RunTask(System.Action)":"Akka.Dispatch.ActorTaskScheduler.yml","Akka.Dispatch.ActorTaskScheduler.RunTask(System.Func{System.Threading.Tasks.Task})":"Akka.Dispatch.ActorTaskScheduler.yml","Akka.Dispatch.CurrentSynchronizationContextDispatcher":"Akka.Dispatch.CurrentSynchronizationContextDispatcher.yml","Akka.Dispatch.CurrentSynchronizationContextDispatcher.#ctor(Akka.Dispatch.MessageDispatcherConfigurator,System.String,System.Int32,System.Nullable{System.Int64},Akka.Dispatch.ExecutorServiceFactory,System.TimeSpan)":"Akka.Dispatch.CurrentSynchronizationContextDispatcher.yml","Akka.Dispatch.Dispatcher":"Akka.Dispatch.Dispatcher.yml","Akka.Dispatch.Dispatcher.#ctor(Akka.Dispatch.MessageDispatcherConfigurator,System.String,System.Int32,System.Nullable{System.Int64},Akka.Dispatch.ExecutorServiceFactory,System.TimeSpan)":"Akka.Dispatch.Dispatcher.yml","Akka.Dispatch.Dispatcher.ExecuteTask(Akka.Dispatch.IRunnable)":"Akka.Dispatch.Dispatcher.yml","Akka.Dispatch.Dispatcher.Shutdown":"Akka.Dispatch.Dispatcher.yml","Akka.Dispatch.ExecutorService":"Akka.Dispatch.ExecutorService.yml","Akka.Dispatch.ExecutorService.#ctor(System.String)":"Akka.Dispatch.ExecutorService.yml","Akka.Dispatch.ExecutorService.Id":"Akka.Dispatch.ExecutorService.yml","Akka.Dispatch.ExecutorService.Execute(Akka.Dispatch.IRunnable)":"Akka.Dispatch.ExecutorService.yml","Akka.Dispatch.ExecutorService.Shutdown":"Akka.Dispatch.ExecutorService.yml","Akka.Dispatch.ExecutorServiceFactory":"Akka.Dispatch.ExecutorServiceFactory.yml","Akka.Dispatch.ExecutorServiceFactory.Produce(System.String)":"Akka.Dispatch.ExecutorServiceFactory.yml","Akka.Dispatch.RejectedExecutionException":"Akka.Dispatch.RejectedExecutionException.yml","Akka.Dispatch.RejectedExecutionException.#ctor(System.String,System.Exception)":"Akka.Dispatch.RejectedExecutionException.yml","Akka.Dispatch.Dispatchers":"Akka.Dispatch.Dispatchers.yml","Akka.Dispatch.Dispatchers.DefaultDispatcherId":"Akka.Dispatch.Dispatchers.yml","Akka.Dispatch.Dispatchers.SynchronizedDispatcherId":"Akka.Dispatch.Dispatchers.yml","Akka.Dispatch.Dispatchers.#ctor(Akka.Actor.ActorSystem,Akka.Dispatch.IDispatcherPrerequisites)":"Akka.Dispatch.Dispatchers.yml","Akka.Dispatch.Dispatchers.DefaultGlobalDispatcher":"Akka.Dispatch.Dispatchers.yml","Akka.Dispatch.Dispatchers.DefaultDispatcherConfig":"Akka.Dispatch.Dispatchers.yml","Akka.Dispatch.Dispatchers.Prerequisites":"Akka.Dispatch.Dispatchers.yml","Akka.Dispatch.Dispatchers.Lookup(System.String)":"Akka.Dispatch.Dispatchers.yml","Akka.Dispatch.Dispatchers.HasDispatcher(System.String)":"Akka.Dispatch.Dispatchers.yml","Akka.Dispatch.Dispatchers.RegisterConfigurator(System.String,Akka.Dispatch.MessageDispatcherConfigurator)":"Akka.Dispatch.Dispatchers.yml","Akka.Dispatch.DispatcherConfigurator":"Akka.Dispatch.DispatcherConfigurator.yml","Akka.Dispatch.DispatcherConfigurator.#ctor(Akka.Configuration.Config,Akka.Dispatch.IDispatcherPrerequisites)":"Akka.Dispatch.DispatcherConfigurator.yml","Akka.Dispatch.DispatcherConfigurator.Dispatcher":"Akka.Dispatch.DispatcherConfigurator.yml","Akka.Dispatch.IRunnable":"Akka.Dispatch.IRunnable.yml","Akka.Dispatch.IRunnable.Run":"Akka.Dispatch.IRunnable.yml","Akka.Dispatch.ActionRunnable":"Akka.Dispatch.ActionRunnable.yml","Akka.Dispatch.ActionRunnable.#ctor(System.Action)":"Akka.Dispatch.ActionRunnable.yml","Akka.Dispatch.ActionRunnable.Run":"Akka.Dispatch.ActionRunnable.yml","Akka.Dispatch.ActionWithStateRunnable":"Akka.Dispatch.ActionWithStateRunnable.yml","Akka.Dispatch.ActionWithStateRunnable.#ctor(System.Action{System.Object},System.Object)":"Akka.Dispatch.ActionWithStateRunnable.yml","Akka.Dispatch.ActionWithStateRunnable.Run":"Akka.Dispatch.ActionWithStateRunnable.yml","Akka.Dispatch.ISemantics":"Akka.Dispatch.ISemantics.yml","Akka.Dispatch.IMultipleConsumerSemantics":"Akka.Dispatch.IMultipleConsumerSemantics.yml","Akka.Dispatch.IUnboundedMessageQueueSemantics":"Akka.Dispatch.IUnboundedMessageQueueSemantics.yml","Akka.Dispatch.IBoundedMessageQueueSemantics":"Akka.Dispatch.IBoundedMessageQueueSemantics.yml","Akka.Dispatch.IBoundedMessageQueueSemantics.PushTimeOut":"Akka.Dispatch.IBoundedMessageQueueSemantics.yml","Akka.Dispatch.IBlockingMessageQueueSemantics":"Akka.Dispatch.IBlockingMessageQueueSemantics.yml","Akka.Dispatch.IBlockingMessageQueueSemantics.BlockTimeOut":"Akka.Dispatch.IBlockingMessageQueueSemantics.yml","Akka.Dispatch.IDequeBasedMessageQueueSemantics":"Akka.Dispatch.IDequeBasedMessageQueueSemantics.yml","Akka.Dispatch.IDequeBasedMessageQueueSemantics.EnqueueFirst(Akka.Actor.Envelope)":"Akka.Dispatch.IDequeBasedMessageQueueSemantics.yml","Akka.Dispatch.IUnboundedDequeBasedMessageQueueSemantics":"Akka.Dispatch.IUnboundedDequeBasedMessageQueueSemantics.yml","Akka.Dispatch.IBoundedDequeBasedMessageQueueSemantics":"Akka.Dispatch.IBoundedDequeBasedMessageQueueSemantics.yml","Akka.Dispatch.FutureActor":"Akka.Dispatch.FutureActor.yml","Akka.Dispatch.FutureActor.#ctor":"Akka.Dispatch.FutureActor.yml","Akka.Dispatch.FutureActor.#ctor(System.Threading.Tasks.TaskCompletionSource{System.Object},Akka.Actor.IActorRef)":"Akka.Dispatch.FutureActor.yml","Akka.Dispatch.FutureActor.Receive(System.Object)":"Akka.Dispatch.FutureActor.yml","Akka.Dispatch.Mailbox":"Akka.Dispatch.Mailbox.yml","Akka.Dispatch.Mailbox.MessageQueue":"Akka.Dispatch.Mailbox.yml","Akka.Dispatch.Mailbox.#ctor(Akka.Dispatch.MessageQueues.IMessageQueue)":"Akka.Dispatch.Mailbox.yml","Akka.Dispatch.Mailbox.Dispatcher":"Akka.Dispatch.Mailbox.yml","Akka.Dispatch.Mailbox.SetActor(Akka.Actor.ActorCell)":"Akka.Dispatch.Mailbox.yml","Akka.Dispatch.Mailbox.Run":"Akka.Dispatch.Mailbox.yml","Akka.Dispatch.Mailbox.CleanUp":"Akka.Dispatch.Mailbox.yml","Akka.Dispatch.Mailbox.DebugPrint(System.String,System.Object[])":"Akka.Dispatch.Mailbox.yml","Akka.Dispatch.MailboxType":"Akka.Dispatch.MailboxType.yml","Akka.Dispatch.MailboxType.Settings":"Akka.Dispatch.MailboxType.yml","Akka.Dispatch.MailboxType.Config":"Akka.Dispatch.MailboxType.yml","Akka.Dispatch.MailboxType.#ctor(Akka.Actor.Settings,Akka.Configuration.Config)":"Akka.Dispatch.MailboxType.yml","Akka.Dispatch.MailboxType.Create(Akka.Actor.IActorRef,Akka.Actor.ActorSystem)":"Akka.Dispatch.MailboxType.yml","Akka.Dispatch.IProducesMessageQueue`1":"Akka.Dispatch.IProducesMessageQueue-1.yml","Akka.Dispatch.UnboundedMailbox":"Akka.Dispatch.UnboundedMailbox.yml","Akka.Dispatch.UnboundedMailbox.Create(Akka.Actor.IActorRef,Akka.Actor.ActorSystem)":"Akka.Dispatch.UnboundedMailbox.yml","Akka.Dispatch.UnboundedMailbox.#ctor":"Akka.Dispatch.UnboundedMailbox.yml","Akka.Dispatch.UnboundedMailbox.#ctor(Akka.Actor.Settings,Akka.Configuration.Config)":"Akka.Dispatch.UnboundedMailbox.yml","Akka.Dispatch.BoundedMailbox":"Akka.Dispatch.BoundedMailbox.yml","Akka.Dispatch.BoundedMailbox.Capacity":"Akka.Dispatch.BoundedMailbox.yml","Akka.Dispatch.BoundedMailbox.PushTimeout":"Akka.Dispatch.BoundedMailbox.yml","Akka.Dispatch.BoundedMailbox.#ctor(Akka.Actor.Settings,Akka.Configuration.Config)":"Akka.Dispatch.BoundedMailbox.yml","Akka.Dispatch.BoundedMailbox.Create(Akka.Actor.IActorRef,Akka.Actor.ActorSystem)":"Akka.Dispatch.BoundedMailbox.yml","Akka.Dispatch.UnboundedPriorityMailbox":"Akka.Dispatch.UnboundedPriorityMailbox.yml","Akka.Dispatch.UnboundedPriorityMailbox.PriorityGenerator(System.Object)":"Akka.Dispatch.UnboundedPriorityMailbox.yml","Akka.Dispatch.UnboundedPriorityMailbox.InitialCapacity":"Akka.Dispatch.UnboundedPriorityMailbox.yml","Akka.Dispatch.UnboundedPriorityMailbox.DefaultCapacity":"Akka.Dispatch.UnboundedPriorityMailbox.yml","Akka.Dispatch.UnboundedPriorityMailbox.Create(Akka.Actor.IActorRef,Akka.Actor.ActorSystem)":"Akka.Dispatch.UnboundedPriorityMailbox.yml","Akka.Dispatch.UnboundedPriorityMailbox.#ctor(Akka.Actor.Settings,Akka.Configuration.Config)":"Akka.Dispatch.UnboundedPriorityMailbox.yml","Akka.Dispatch.UnboundedDequeBasedMailbox":"Akka.Dispatch.UnboundedDequeBasedMailbox.yml","Akka.Dispatch.UnboundedDequeBasedMailbox.#ctor(Akka.Actor.Settings,Akka.Configuration.Config)":"Akka.Dispatch.UnboundedDequeBasedMailbox.yml","Akka.Dispatch.UnboundedDequeBasedMailbox.Create(Akka.Actor.IActorRef,Akka.Actor.ActorSystem)":"Akka.Dispatch.UnboundedDequeBasedMailbox.yml","Akka.Dispatch.BoundedDequeBasedMailbox":"Akka.Dispatch.BoundedDequeBasedMailbox.yml","Akka.Dispatch.BoundedDequeBasedMailbox.Capacity":"Akka.Dispatch.BoundedDequeBasedMailbox.yml","Akka.Dispatch.BoundedDequeBasedMailbox.PushTimeout":"Akka.Dispatch.BoundedDequeBasedMailbox.yml","Akka.Dispatch.BoundedDequeBasedMailbox.#ctor(Akka.Actor.Settings,Akka.Configuration.Config)":"Akka.Dispatch.BoundedDequeBasedMailbox.yml","Akka.Dispatch.BoundedDequeBasedMailbox.Create(Akka.Actor.IActorRef,Akka.Actor.ActorSystem)":"Akka.Dispatch.BoundedDequeBasedMailbox.yml","Akka.Dispatch.Mailboxes":"Akka.Dispatch.Mailboxes.yml","Akka.Dispatch.Mailboxes.DefaultMailboxId":"Akka.Dispatch.Mailboxes.yml","Akka.Dispatch.Mailboxes.NoMailboxRequirement":"Akka.Dispatch.Mailboxes.yml","Akka.Dispatch.Mailboxes.#ctor(Akka.Actor.ActorSystem)":"Akka.Dispatch.Mailboxes.yml","Akka.Dispatch.Mailboxes.DeadLetterMailbox":"Akka.Dispatch.Mailboxes.yml","Akka.Dispatch.Mailboxes.HasRequiredType(System.Type)":"Akka.Dispatch.Mailboxes.yml","Akka.Dispatch.Mailboxes.ProducesMessageQueue(System.Type)":"Akka.Dispatch.Mailboxes.yml","Akka.Dispatch.Mailboxes.LookupByQueueType(System.Type)":"Akka.Dispatch.Mailboxes.yml","Akka.Dispatch.Mailboxes.Lookup(System.String)":"Akka.Dispatch.Mailboxes.yml","Akka.Dispatch.Mailboxes.GetRequiredType(System.Type)":"Akka.Dispatch.Mailboxes.yml","Akka.Dispatch.Mailboxes.GetMailboxType(Akka.Actor.Props,Akka.Configuration.Config)":"Akka.Dispatch.Mailboxes.yml","Akka.Dispatch.Mailboxes.FromConfig(System.String)":"Akka.Dispatch.Mailboxes.yml","Akka.Dispatch.PinnedDispatcher":"Akka.Dispatch.PinnedDispatcher.yml","Akka.Dispatch.PinnedDispatcher.#ctor(Akka.Dispatch.MessageDispatcherConfigurator,System.String,System.Int32,System.Nullable{System.Int64},Akka.Dispatch.ExecutorServiceFactory,System.TimeSpan)":"Akka.Dispatch.PinnedDispatcher.yml","Akka.Dispatch.ThreadPoolConfig":"Akka.Dispatch.ThreadPoolConfig.yml","Akka.Dispatch.ThreadPoolConfig.#ctor(Akka.Configuration.Config)":"Akka.Dispatch.ThreadPoolConfig.yml","Akka.Dispatch.ThreadPoolConfig.PoolSizeMin":"Akka.Dispatch.ThreadPoolConfig.yml","Akka.Dispatch.ThreadPoolConfig.PoolSizeFactor":"Akka.Dispatch.ThreadPoolConfig.yml","Akka.Dispatch.ThreadPoolConfig.PoolSizeMax":"Akka.Dispatch.ThreadPoolConfig.yml","Akka.Dispatch.ThreadPoolConfig.ScaledPoolSize(System.Int32,System.Double,System.Int32)":"Akka.Dispatch.ThreadPoolConfig.yml","Akka.Dispatch.IRequiresMessageQueue`1":"Akka.Dispatch.IRequiresMessageQueue-1.yml","Akka.Dispatch.MessageQueues":"Akka.Dispatch.MessageQueues.yml","Akka.Dispatch.MessageQueues.BlockingMessageQueue":"Akka.Dispatch.MessageQueues.BlockingMessageQueue.yml","Akka.Dispatch.MessageQueues.BlockingMessageQueue.LockedCount":"Akka.Dispatch.MessageQueues.BlockingMessageQueue.yml","Akka.Dispatch.MessageQueues.BlockingMessageQueue.BlockTimeOut":"Akka.Dispatch.MessageQueues.BlockingMessageQueue.yml","Akka.Dispatch.MessageQueues.BlockingMessageQueue.HasMessages":"Akka.Dispatch.MessageQueues.BlockingMessageQueue.yml","Akka.Dispatch.MessageQueues.BlockingMessageQueue.Count":"Akka.Dispatch.MessageQueues.BlockingMessageQueue.yml","Akka.Dispatch.MessageQueues.BlockingMessageQueue.Enqueue(Akka.Actor.IActorRef,Akka.Actor.Envelope)":"Akka.Dispatch.MessageQueues.BlockingMessageQueue.yml","Akka.Dispatch.MessageQueues.BlockingMessageQueue.TryDequeue(Akka.Actor.Envelope@)":"Akka.Dispatch.MessageQueues.BlockingMessageQueue.yml","Akka.Dispatch.MessageQueues.BlockingMessageQueue.CleanUp(Akka.Actor.IActorRef,Akka.Dispatch.MessageQueues.IMessageQueue)":"Akka.Dispatch.MessageQueues.BlockingMessageQueue.yml","Akka.Dispatch.MessageQueues.BlockingMessageQueue.LockedEnqueue(Akka.Actor.Envelope)":"Akka.Dispatch.MessageQueues.BlockingMessageQueue.yml","Akka.Dispatch.MessageQueues.BlockingMessageQueue.LockedTryDequeue(Akka.Actor.Envelope@)":"Akka.Dispatch.MessageQueues.BlockingMessageQueue.yml","Akka.Dispatch.MessageQueues.BoundedMessageQueue":"Akka.Dispatch.MessageQueues.BoundedMessageQueue.yml","Akka.Dispatch.MessageQueues.BoundedMessageQueue.#ctor(Akka.Configuration.Config)":"Akka.Dispatch.MessageQueues.BoundedMessageQueue.yml","Akka.Dispatch.MessageQueues.BoundedMessageQueue.#ctor(System.Int32,System.TimeSpan)":"Akka.Dispatch.MessageQueues.BoundedMessageQueue.yml","Akka.Dispatch.MessageQueues.BoundedMessageQueue.HasMessages":"Akka.Dispatch.MessageQueues.BoundedMessageQueue.yml","Akka.Dispatch.MessageQueues.BoundedMessageQueue.Count":"Akka.Dispatch.MessageQueues.BoundedMessageQueue.yml","Akka.Dispatch.MessageQueues.BoundedMessageQueue.Enqueue(Akka.Actor.IActorRef,Akka.Actor.Envelope)":"Akka.Dispatch.MessageQueues.BoundedMessageQueue.yml","Akka.Dispatch.MessageQueues.BoundedMessageQueue.TryDequeue(Akka.Actor.Envelope@)":"Akka.Dispatch.MessageQueues.BoundedMessageQueue.yml","Akka.Dispatch.MessageQueues.BoundedMessageQueue.CleanUp(Akka.Actor.IActorRef,Akka.Dispatch.MessageQueues.IMessageQueue)":"Akka.Dispatch.MessageQueues.BoundedMessageQueue.yml","Akka.Dispatch.MessageQueues.BoundedMessageQueue.PushTimeOut":"Akka.Dispatch.MessageQueues.BoundedMessageQueue.yml","Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue":"Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.yml","Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.MessageQueue":"Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.yml","Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.#ctor(Akka.Dispatch.MessageQueues.IMessageQueue)":"Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.yml","Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.HasMessages":"Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.yml","Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.Count":"Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.yml","Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.Enqueue(Akka.Actor.IActorRef,Akka.Actor.Envelope)":"Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.yml","Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.TryDequeue(Akka.Actor.Envelope@)":"Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.yml","Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.CleanUp(Akka.Actor.IActorRef,Akka.Dispatch.MessageQueues.IMessageQueue)":"Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.yml","Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.EnqueueFirst(Akka.Actor.Envelope)":"Akka.Dispatch.MessageQueues.DequeWrapperMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedDequeMessageQueue":"Akka.Dispatch.MessageQueues.UnboundedDequeMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedDequeMessageQueue.#ctor":"Akka.Dispatch.MessageQueues.UnboundedDequeMessageQueue.yml","Akka.Dispatch.MessageQueues.BoundedDequeMessageQueue":"Akka.Dispatch.MessageQueues.BoundedDequeMessageQueue.yml","Akka.Dispatch.MessageQueues.BoundedDequeMessageQueue.#ctor(System.Int32,System.TimeSpan)":"Akka.Dispatch.MessageQueues.BoundedDequeMessageQueue.yml","Akka.Dispatch.MessageQueues.BoundedDequeMessageQueue.PushTimeOut":"Akka.Dispatch.MessageQueues.BoundedDequeMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedPriorityMessageQueue":"Akka.Dispatch.MessageQueues.UnboundedPriorityMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedPriorityMessageQueue.#ctor(System.Int32)":"Akka.Dispatch.MessageQueues.UnboundedPriorityMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedPriorityMessageQueue.#ctor(System.Func{System.Object,System.Int32},System.Int32)":"Akka.Dispatch.MessageQueues.UnboundedPriorityMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedPriorityMessageQueue.LockedCount":"Akka.Dispatch.MessageQueues.UnboundedPriorityMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedPriorityMessageQueue.LockedEnqueue(Akka.Actor.Envelope)":"Akka.Dispatch.MessageQueues.UnboundedPriorityMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedPriorityMessageQueue.LockedTryDequeue(Akka.Actor.Envelope@)":"Akka.Dispatch.MessageQueues.UnboundedPriorityMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedMessageQueue":"Akka.Dispatch.MessageQueues.UnboundedMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedMessageQueue.HasMessages":"Akka.Dispatch.MessageQueues.UnboundedMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedMessageQueue.Count":"Akka.Dispatch.MessageQueues.UnboundedMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedMessageQueue.Enqueue(Akka.Actor.IActorRef,Akka.Actor.Envelope)":"Akka.Dispatch.MessageQueues.UnboundedMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedMessageQueue.TryDequeue(Akka.Actor.Envelope@)":"Akka.Dispatch.MessageQueues.UnboundedMessageQueue.yml","Akka.Dispatch.MessageQueues.UnboundedMessageQueue.CleanUp(Akka.Actor.IActorRef,Akka.Dispatch.MessageQueues.IMessageQueue)":"Akka.Dispatch.MessageQueues.UnboundedMessageQueue.yml","Akka.Dispatch.MessageQueues.IMessageQueue":"Akka.Dispatch.MessageQueues.IMessageQueue.yml","Akka.Dispatch.MessageQueues.IMessageQueue.HasMessages":"Akka.Dispatch.MessageQueues.IMessageQueue.yml","Akka.Dispatch.MessageQueues.IMessageQueue.Count":"Akka.Dispatch.MessageQueues.IMessageQueue.yml","Akka.Dispatch.MessageQueues.IMessageQueue.Enqueue(Akka.Actor.IActorRef,Akka.Actor.Envelope)":"Akka.Dispatch.MessageQueues.IMessageQueue.yml","Akka.Dispatch.MessageQueues.IMessageQueue.TryDequeue(Akka.Actor.Envelope@)":"Akka.Dispatch.MessageQueues.IMessageQueue.yml","Akka.Dispatch.MessageQueues.IMessageQueue.CleanUp(Akka.Actor.IActorRef,Akka.Dispatch.MessageQueues.IMessageQueue)":"Akka.Dispatch.MessageQueues.IMessageQueue.yml","Akka.Dispatch.SysMsg":"Akka.Dispatch.SysMsg.yml","Akka.Dispatch.SysMsg.ISystemMessage":"Akka.Dispatch.SysMsg.ISystemMessage.yml","Akka.Dispatch.SysMsg.SystemMessage":"Akka.Dispatch.SysMsg.SystemMessage.yml","Akka.Dispatch.SysMsg.SystemMessage.Unlink":"Akka.Dispatch.SysMsg.SystemMessage.yml","Akka.Dispatch.SysMsg.SystemMessage.Unlinked":"Akka.Dispatch.SysMsg.SystemMessage.yml","Akka.Dispatch.SysMsg.NoMessage":"Akka.Dispatch.SysMsg.NoMessage.yml","Akka.Dispatch.SysMsg.NoMessage.ToString":"Akka.Dispatch.SysMsg.NoMessage.yml","Akka.Dispatch.SysMsg.DeathWatchNotification":"Akka.Dispatch.SysMsg.DeathWatchNotification.yml","Akka.Dispatch.SysMsg.DeathWatchNotification.#ctor(Akka.Actor.IActorRef,System.Boolean,System.Boolean)":"Akka.Dispatch.SysMsg.DeathWatchNotification.yml","Akka.Dispatch.SysMsg.DeathWatchNotification.Actor":"Akka.Dispatch.SysMsg.DeathWatchNotification.yml","Akka.Dispatch.SysMsg.DeathWatchNotification.ExistenceConfirmed":"Akka.Dispatch.SysMsg.DeathWatchNotification.yml","Akka.Dispatch.SysMsg.DeathWatchNotification.AddressTerminated":"Akka.Dispatch.SysMsg.DeathWatchNotification.yml","Akka.Dispatch.SysMsg.DeathWatchNotification.ToString":"Akka.Dispatch.SysMsg.DeathWatchNotification.yml","Akka.Dispatch.SysMsg.Failed":"Akka.Dispatch.SysMsg.Failed.yml","Akka.Dispatch.SysMsg.Failed.#ctor(Akka.Actor.IActorRef,System.Exception,System.Int64)":"Akka.Dispatch.SysMsg.Failed.yml","Akka.Dispatch.SysMsg.Failed.Child":"Akka.Dispatch.SysMsg.Failed.yml","Akka.Dispatch.SysMsg.Failed.Cause":"Akka.Dispatch.SysMsg.Failed.yml","Akka.Dispatch.SysMsg.Failed.Uid":"Akka.Dispatch.SysMsg.Failed.yml","Akka.Dispatch.SysMsg.Failed.ToString":"Akka.Dispatch.SysMsg.Failed.yml","Akka.Dispatch.SysMsg.Supervise":"Akka.Dispatch.SysMsg.Supervise.yml","Akka.Dispatch.SysMsg.Supervise.#ctor(Akka.Actor.IActorRef,System.Boolean)":"Akka.Dispatch.SysMsg.Supervise.yml","Akka.Dispatch.SysMsg.Supervise.Async":"Akka.Dispatch.SysMsg.Supervise.yml","Akka.Dispatch.SysMsg.Supervise.Child":"Akka.Dispatch.SysMsg.Supervise.yml","Akka.Dispatch.SysMsg.Supervise.ToString":"Akka.Dispatch.SysMsg.Supervise.yml","Akka.Dispatch.SysMsg.Watch":"Akka.Dispatch.SysMsg.Watch.yml","Akka.Dispatch.SysMsg.Watch.#ctor(Akka.Actor.IInternalActorRef,Akka.Actor.IInternalActorRef)":"Akka.Dispatch.SysMsg.Watch.yml","Akka.Dispatch.SysMsg.Watch.Watchee":"Akka.Dispatch.SysMsg.Watch.yml","Akka.Dispatch.SysMsg.Watch.Watcher":"Akka.Dispatch.SysMsg.Watch.yml","Akka.Dispatch.SysMsg.Watch.ToString":"Akka.Dispatch.SysMsg.Watch.yml","Akka.Dispatch.SysMsg.Unwatch":"Akka.Dispatch.SysMsg.Unwatch.yml","Akka.Dispatch.SysMsg.Unwatch.#ctor(Akka.Actor.IInternalActorRef,Akka.Actor.IInternalActorRef)":"Akka.Dispatch.SysMsg.Unwatch.yml","Akka.Dispatch.SysMsg.Unwatch.Watchee":"Akka.Dispatch.SysMsg.Unwatch.yml","Akka.Dispatch.SysMsg.Unwatch.Watcher":"Akka.Dispatch.SysMsg.Unwatch.yml","Akka.Dispatch.SysMsg.Unwatch.ToString":"Akka.Dispatch.SysMsg.Unwatch.yml","Akka.Dispatch.SysMsg.ActorTask":"Akka.Dispatch.SysMsg.ActorTask.yml","Akka.Dispatch.SysMsg.ActorTask.#ctor(System.Threading.Tasks.Task)":"Akka.Dispatch.SysMsg.ActorTask.yml","Akka.Dispatch.SysMsg.ActorTask.Task":"Akka.Dispatch.SysMsg.ActorTask.yml","Akka.Dispatch.SysMsg.Recreate":"Akka.Dispatch.SysMsg.Recreate.yml","Akka.Dispatch.SysMsg.Recreate.#ctor(System.Exception)":"Akka.Dispatch.SysMsg.Recreate.yml","Akka.Dispatch.SysMsg.Recreate.Cause":"Akka.Dispatch.SysMsg.Recreate.yml","Akka.Dispatch.SysMsg.Recreate.ToString":"Akka.Dispatch.SysMsg.Recreate.yml","Akka.Dispatch.SysMsg.Resume":"Akka.Dispatch.SysMsg.Resume.yml","Akka.Dispatch.SysMsg.Resume.#ctor(System.Exception)":"Akka.Dispatch.SysMsg.Resume.yml","Akka.Dispatch.SysMsg.Resume.CausedByFailure":"Akka.Dispatch.SysMsg.Resume.yml","Akka.Dispatch.SysMsg.Resume.ToString":"Akka.Dispatch.SysMsg.Resume.yml","Akka.Dispatch.SysMsg.Suspend":"Akka.Dispatch.SysMsg.Suspend.yml","Akka.Dispatch.SysMsg.Suspend.ToString":"Akka.Dispatch.SysMsg.Suspend.yml","Akka.Dispatch.SysMsg.Stop":"Akka.Dispatch.SysMsg.Stop.yml","Akka.Dispatch.SysMsg.Stop.ToString":"Akka.Dispatch.SysMsg.Stop.yml","Akka.Dispatch.SysMsg.StopChild":"Akka.Dispatch.SysMsg.StopChild.yml","Akka.Dispatch.SysMsg.StopChild.#ctor(Akka.Actor.IActorRef)":"Akka.Dispatch.SysMsg.StopChild.yml","Akka.Dispatch.SysMsg.StopChild.Child":"Akka.Dispatch.SysMsg.StopChild.yml","Akka.Dispatch.SysMsg.StopChild.ToString":"Akka.Dispatch.SysMsg.StopChild.yml","Akka.Dispatch.SysMsg.Escalate":"Akka.Dispatch.SysMsg.Escalate.yml","Akka.Dispatch.SysMsg.Escalate.#ctor(System.Exception)":"Akka.Dispatch.SysMsg.Escalate.yml","Akka.Dispatch.SysMsg.Escalate.Reason":"Akka.Dispatch.SysMsg.Escalate.yml","Akka.Dispatch.SysMsg.Escalate.ToString":"Akka.Dispatch.SysMsg.Escalate.yml","Akka.Dispatch.SysMsg.Terminate":"Akka.Dispatch.SysMsg.Terminate.yml","Akka.Dispatch.SysMsg.Terminate.ToString":"Akka.Dispatch.SysMsg.Terminate.yml","Akka.Dispatch.SysMsg.Create":"Akka.Dispatch.SysMsg.Create.yml","Akka.Dispatch.SysMsg.Create.#ctor(Akka.Actor.ActorInitializationException)":"Akka.Dispatch.SysMsg.Create.yml","Akka.Dispatch.SysMsg.Create.Failure":"Akka.Dispatch.SysMsg.Create.yml","Akka.Dispatch.SysMsg.Create.ToString":"Akka.Dispatch.SysMsg.Create.yml","Akka.Dispatch.SysMsg.RegisterTerminationHook":"Akka.Dispatch.SysMsg.RegisterTerminationHook.yml","Akka.Dispatch.SysMsg.RegisterTerminationHook.Instance":"Akka.Dispatch.SysMsg.RegisterTerminationHook.yml","Akka.Dispatch.SysMsg.RegisterTerminationHook.ToString":"Akka.Dispatch.SysMsg.RegisterTerminationHook.yml","Akka.Dispatch.SysMsg.TerminationHook":"Akka.Dispatch.SysMsg.TerminationHook.yml","Akka.Dispatch.SysMsg.TerminationHook.Instance":"Akka.Dispatch.SysMsg.TerminationHook.yml","Akka.Dispatch.SysMsg.TerminationHook.ToString":"Akka.Dispatch.SysMsg.TerminationHook.yml","Akka.Dispatch.SysMsg.TerminationHookDone":"Akka.Dispatch.SysMsg.TerminationHookDone.yml","Akka.Dispatch.SysMsg.TerminationHookDone.Instance":"Akka.Dispatch.SysMsg.TerminationHookDone.yml","Akka.Dispatch.SysMsg.TerminationHookDone.ToString":"Akka.Dispatch.SysMsg.TerminationHookDone.yml","Akka.Event":"Akka.Event.yml","Akka.Event.ActorEventBus`2":"Akka.Event.ActorEventBus-2.yml","Akka.Event.BusLogging":"Akka.Event.BusLogging.yml","Akka.Event.BusLogging.#ctor(Akka.Event.LoggingBus,System.String,System.Type,Akka.Event.ILogMessageFormatter)":"Akka.Event.BusLogging.yml","Akka.Event.BusLogging.IsDebugEnabled":"Akka.Event.BusLogging.yml","Akka.Event.BusLogging.IsErrorEnabled":"Akka.Event.BusLogging.yml","Akka.Event.BusLogging.IsInfoEnabled":"Akka.Event.BusLogging.yml","Akka.Event.BusLogging.IsWarningEnabled":"Akka.Event.BusLogging.yml","Akka.Event.BusLogging.NotifyError(System.Object)":"Akka.Event.BusLogging.yml","Akka.Event.BusLogging.NotifyError(System.Exception,System.Object)":"Akka.Event.BusLogging.yml","Akka.Event.BusLogging.NotifyWarning(System.Object)":"Akka.Event.BusLogging.yml","Akka.Event.BusLogging.NotifyInfo(System.Object)":"Akka.Event.BusLogging.yml","Akka.Event.BusLogging.NotifyDebug(System.Object)":"Akka.Event.BusLogging.yml","Akka.Event.IDeadLetterSuppression":"Akka.Event.IDeadLetterSuppression.yml","Akka.Event.AllDeadLetters":"Akka.Event.AllDeadLetters.yml","Akka.Event.AllDeadLetters.#ctor(System.Object,Akka.Actor.IActorRef,Akka.Actor.IActorRef)":"Akka.Event.AllDeadLetters.yml","Akka.Event.AllDeadLetters.Message":"Akka.Event.AllDeadLetters.yml","Akka.Event.AllDeadLetters.Recipient":"Akka.Event.AllDeadLetters.yml","Akka.Event.AllDeadLetters.Sender":"Akka.Event.AllDeadLetters.yml","Akka.Event.AllDeadLetters.ToString":"Akka.Event.AllDeadLetters.yml","Akka.Event.DeadLetter":"Akka.Event.DeadLetter.yml","Akka.Event.DeadLetter.#ctor(System.Object,Akka.Actor.IActorRef,Akka.Actor.IActorRef)":"Akka.Event.DeadLetter.yml","Akka.Event.SuppressedDeadLetter":"Akka.Event.SuppressedDeadLetter.yml","Akka.Event.SuppressedDeadLetter.#ctor(Akka.Event.IDeadLetterSuppression,Akka.Actor.IActorRef,Akka.Actor.IActorRef)":"Akka.Event.SuppressedDeadLetter.yml","Akka.Event.DeadLetterListener":"Akka.Event.DeadLetterListener.yml","Akka.Event.DeadLetterListener.PostRestart(System.Exception)":"Akka.Event.DeadLetterListener.yml","Akka.Event.DeadLetterListener.PreStart":"Akka.Event.DeadLetterListener.yml","Akka.Event.DeadLetterListener.PostStop":"Akka.Event.DeadLetterListener.yml","Akka.Event.DeadLetterListener.Receive(System.Object)":"Akka.Event.DeadLetterListener.yml","Akka.Event.Debug":"Akka.Event.Debug.yml","Akka.Event.Debug.#ctor(System.String,System.Type,System.Object)":"Akka.Event.Debug.yml","Akka.Event.Debug.LogLevel":"Akka.Event.Debug.yml","Akka.Event.DefaultLogger":"Akka.Event.DefaultLogger.yml","Akka.Event.DefaultLogger.Receive(System.Object)":"Akka.Event.DefaultLogger.yml","Akka.Event.DefaultLogger.Print(Akka.Event.LogEvent)":"Akka.Event.DefaultLogger.yml","Akka.Event.DefaultLogMessageFormatter":"Akka.Event.DefaultLogMessageFormatter.yml","Akka.Event.DefaultLogMessageFormatter.Format(System.String,System.Object[])":"Akka.Event.DefaultLogMessageFormatter.yml","Akka.Event.Error":"Akka.Event.Error.yml","Akka.Event.Error.#ctor(System.Exception,System.String,System.Type,System.Object)":"Akka.Event.Error.yml","Akka.Event.Error.Cause":"Akka.Event.Error.yml","Akka.Event.Error.LogLevel":"Akka.Event.Error.yml","Akka.Event.Error.ToString":"Akka.Event.Error.yml","Akka.Event.EventBus`3":"Akka.Event.EventBus-3.yml","Akka.Event.EventBus`3.SimpleName(System.Object)":"Akka.Event.EventBus-3.yml","Akka.Event.EventBus`3.SimpleName(System.Type)":"Akka.Event.EventBus-3.yml","Akka.Event.EventBus`3.Subscribe(`2,`1)":"Akka.Event.EventBus-3.yml","Akka.Event.EventBus`3.Unsubscribe(`2)":"Akka.Event.EventBus-3.yml","Akka.Event.EventBus`3.Unsubscribe(`2,`1)":"Akka.Event.EventBus-3.yml","Akka.Event.EventBus`3.IsSubClassification(`1,`1)":"Akka.Event.EventBus-3.yml","Akka.Event.EventBus`3.Publish(`0,`2)":"Akka.Event.EventBus-3.yml","Akka.Event.EventBus`3.Classify(`0,`1)":"Akka.Event.EventBus-3.yml","Akka.Event.EventBus`3.GetClassifier(`0)":"Akka.Event.EventBus-3.yml","Akka.Event.EventBus`3.Publish(`0)":"Akka.Event.EventBus-3.yml","Akka.Event.EventStream":"Akka.Event.EventStream.yml","Akka.Event.EventStream.#ctor(System.Boolean)":"Akka.Event.EventStream.yml","Akka.Event.EventStream.Subscribe(Akka.Actor.IActorRef,System.Type)":"Akka.Event.EventStream.yml","Akka.Event.EventStream.Unsubscribe(Akka.Actor.IActorRef,System.Type)":"Akka.Event.EventStream.yml","Akka.Event.EventStream.Unsubscribe(Akka.Actor.IActorRef)":"Akka.Event.EventStream.yml","Akka.Event.EventStream.StartUnsubscriber(Akka.Actor.Internal.ActorSystemImpl)":"Akka.Event.EventStream.yml","Akka.Event.EventStream.InitUnsubscriber(Akka.Actor.IActorRef,Akka.Actor.ActorSystem)":"Akka.Event.EventStream.yml","Akka.Event.EventStreamExtensions":"Akka.Event.EventStreamExtensions.yml","Akka.Event.EventStreamExtensions.Subscribe``1(Akka.Event.EventStream,Akka.Actor.IActorRef)":"Akka.Event.EventStreamExtensions.yml","Akka.Event.EventStreamExtensions.Unsubscribe``1(Akka.Event.EventStream,Akka.Actor.IActorRef)":"Akka.Event.EventStreamExtensions.yml","Akka.Event.ILoggerMessageQueueSemantics":"Akka.Event.ILoggerMessageQueueSemantics.yml","Akka.Event.ILogMessageFormatter":"Akka.Event.ILogMessageFormatter.yml","Akka.Event.ILogMessageFormatter.Format(System.String,System.Object[])":"Akka.Event.ILogMessageFormatter.yml","Akka.Event.Info":"Akka.Event.Info.yml","Akka.Event.Info.#ctor(System.String,System.Type,System.Object)":"Akka.Event.Info.yml","Akka.Event.Info.LogLevel":"Akka.Event.Info.yml","Akka.Event.InitializeLogger":"Akka.Event.InitializeLogger.yml","Akka.Event.InitializeLogger.#ctor(Akka.Event.LoggingBus)":"Akka.Event.InitializeLogger.yml","Akka.Event.InitializeLogger.LoggingBus":"Akka.Event.InitializeLogger.yml","Akka.Event.LogEvent":"Akka.Event.LogEvent.yml","Akka.Event.LogEvent.#ctor":"Akka.Event.LogEvent.yml","Akka.Event.LogEvent.Timestamp":"Akka.Event.LogEvent.yml","Akka.Event.LogEvent.Thread":"Akka.Event.LogEvent.yml","Akka.Event.LogEvent.LogSource":"Akka.Event.LogEvent.yml","Akka.Event.LogEvent.LogClass":"Akka.Event.LogEvent.yml","Akka.Event.LogEvent.Message":"Akka.Event.LogEvent.yml","Akka.Event.LogEvent.LogLevel":"Akka.Event.LogEvent.yml","Akka.Event.LogEvent.ToString":"Akka.Event.LogEvent.yml","Akka.Event.LoggerInitialized":"Akka.Event.LoggerInitialized.yml","Akka.Event.LoggerMailbox":"Akka.Event.LoggerMailbox.yml","Akka.Event.LoggerMailbox.#ctor(Akka.Actor.IActorRef,Akka.Actor.ActorSystem)":"Akka.Event.LoggerMailbox.yml","Akka.Event.LoggerMailbox.Akka#Dispatch#MessageQueues#IMessageQueue#HasMessages":"Akka.Event.LoggerMailbox.yml","Akka.Event.LoggerMailbox.Akka#Dispatch#MessageQueues#IMessageQueue#Count":"Akka.Event.LoggerMailbox.yml","Akka.Event.LoggerMailbox.Akka#Dispatch#MessageQueues#IMessageQueue#Enqueue(Akka.Actor.IActorRef,Akka.Actor.Envelope)":"Akka.Event.LoggerMailbox.yml","Akka.Event.LoggerMailbox.Akka#Dispatch#MessageQueues#IMessageQueue#TryDequeue(Akka.Actor.Envelope@)":"Akka.Event.LoggerMailbox.yml","Akka.Event.LoggerMailbox.Akka#Dispatch#MessageQueues#IMessageQueue#CleanUp(Akka.Actor.IActorRef,Akka.Dispatch.MessageQueues.IMessageQueue)":"Akka.Event.LoggerMailbox.yml","Akka.Event.DummyClassForStringSources":"Akka.Event.DummyClassForStringSources.yml","Akka.Event.Logging":"Akka.Event.Logging.yml","Akka.Event.Logging.StandardOutLogger":"Akka.Event.Logging.yml","Akka.Event.Logging.ClassFor(Akka.Event.LogLevel)":"Akka.Event.Logging.yml","Akka.Event.Logging.StringFor(Akka.Event.LogLevel)":"Akka.Event.Logging.yml","Akka.Event.Logging.GetLogger(Akka.Actor.IActorContext,Akka.Event.ILogMessageFormatter)":"Akka.Event.Logging.yml","Akka.Event.Logging.GetLogger(Akka.Actor.ActorSystem,System.Object,Akka.Event.ILogMessageFormatter)":"Akka.Event.Logging.yml","Akka.Event.Logging.GetLogger(Akka.Event.LoggingBus,System.Object,Akka.Event.ILogMessageFormatter)":"Akka.Event.Logging.yml","Akka.Event.Logging.LogLevelFor(System.String)":"Akka.Event.Logging.yml","Akka.Event.Logging.LogLevelFor``1":"Akka.Event.Logging.yml","Akka.Event.ILoggingAdapter":"Akka.Event.ILoggingAdapter.yml","Akka.Event.ILoggingAdapter.IsDebugEnabled":"Akka.Event.ILoggingAdapter.yml","Akka.Event.ILoggingAdapter.IsInfoEnabled":"Akka.Event.ILoggingAdapter.yml","Akka.Event.ILoggingAdapter.IsWarningEnabled":"Akka.Event.ILoggingAdapter.yml","Akka.Event.ILoggingAdapter.IsErrorEnabled":"Akka.Event.ILoggingAdapter.yml","Akka.Event.ILoggingAdapter.IsEnabled(Akka.Event.LogLevel)":"Akka.Event.ILoggingAdapter.yml","Akka.Event.ILoggingAdapter.Debug(System.String,System.Object[])":"Akka.Event.ILoggingAdapter.yml","Akka.Event.ILoggingAdapter.Info(System.String,System.Object[])":"Akka.Event.ILoggingAdapter.yml","Akka.Event.ILoggingAdapter.Warn(System.String,System.Object[])":"Akka.Event.ILoggingAdapter.yml","Akka.Event.ILoggingAdapter.Warning(System.String,System.Object[])":"Akka.Event.ILoggingAdapter.yml","Akka.Event.ILoggingAdapter.Error(System.String,System.Object[])":"Akka.Event.ILoggingAdapter.yml","Akka.Event.ILoggingAdapter.Error(System.Exception,System.String,System.Object[])":"Akka.Event.ILoggingAdapter.yml","Akka.Event.ILoggingAdapter.Log(Akka.Event.LogLevel,System.String,System.Object[])":"Akka.Event.ILoggingAdapter.yml","Akka.Event.NoLogger":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.Instance":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.IsDebugEnabled":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.IsInfoEnabled":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.IsWarningEnabled":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.IsErrorEnabled":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.IsEnabled(Akka.Event.LogLevel)":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.Debug(System.String,System.Object[])":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.Info(System.String,System.Object[])":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.Warn(System.String,System.Object[])":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.Warning(System.String,System.Object[])":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.Error(System.String,System.Object[])":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.Error(System.Exception,System.String,System.Object[])":"Akka.Event.NoLogger.yml","Akka.Event.NoLogger.Log(Akka.Event.LogLevel,System.String,System.Object[])":"Akka.Event.NoLogger.yml","Akka.Event.LoggingAdapterBase":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.IsDebugEnabled":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.IsErrorEnabled":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.IsInfoEnabled":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.IsWarningEnabled":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.NotifyError(System.Object)":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.NotifyError(System.Exception,System.Object)":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.NotifyWarning(System.Object)":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.NotifyInfo(System.Object)":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.NotifyDebug(System.Object)":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.#ctor(Akka.Event.ILogMessageFormatter)":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.IsEnabled(Akka.Event.LogLevel)":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.NotifyLog(Akka.Event.LogLevel,System.Object)":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.Debug(System.String,System.Object[])":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.Warn(System.String,System.Object[])":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.Warning(System.String,System.Object[])":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.Error(System.Exception,System.String,System.Object[])":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.Error(System.String,System.Object[])":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.Info(System.String,System.Object[])":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingAdapterBase.Log(Akka.Event.LogLevel,System.String,System.Object[])":"Akka.Event.LoggingAdapterBase.yml","Akka.Event.LoggingBus":"Akka.Event.LoggingBus.yml","Akka.Event.LoggingBus.LogLevel":"Akka.Event.LoggingBus.yml","Akka.Event.LoggingBus.IsSubClassification(System.Type,System.Type)":"Akka.Event.LoggingBus.yml","Akka.Event.LoggingBus.Publish(System.Object,Akka.Actor.IActorRef)":"Akka.Event.LoggingBus.yml","Akka.Event.LoggingBus.Classify(System.Object,System.Type)":"Akka.Event.LoggingBus.yml","Akka.Event.LoggingBus.GetClassifier(System.Object)":"Akka.Event.LoggingBus.yml","Akka.Event.LoggingBus.StartStdoutLogger(Akka.Actor.Settings)":"Akka.Event.LoggingBus.yml","Akka.Event.LoggingBus.SetLogLevel(Akka.Event.LogLevel)":"Akka.Event.LoggingBus.yml","Akka.Event.LogLevel":"Akka.Event.LogLevel.yml","Akka.Event.LogLevel.DebugLevel":"Akka.Event.LogLevel.yml","Akka.Event.LogLevel.InfoLevel":"Akka.Event.LogLevel.yml","Akka.Event.LogLevel.WarningLevel":"Akka.Event.LogLevel.yml","Akka.Event.LogLevel.ErrorLevel":"Akka.Event.LogLevel.yml","Akka.Event.LogMessage":"Akka.Event.LogMessage.yml","Akka.Event.LogMessage.Format":"Akka.Event.LogMessage.yml","Akka.Event.LogMessage.Args":"Akka.Event.LogMessage.yml","Akka.Event.LogMessage.#ctor(Akka.Event.ILogMessageFormatter,System.String,System.Object[])":"Akka.Event.LogMessage.yml","Akka.Event.LogMessage.ToString":"Akka.Event.LogMessage.yml","Akka.Event.StandardOutLogger":"Akka.Event.StandardOutLogger.yml","Akka.Event.StandardOutLogger.Provider":"Akka.Event.StandardOutLogger.yml","Akka.Event.StandardOutLogger.Path":"Akka.Event.StandardOutLogger.yml","Akka.Event.StandardOutLogger.TellInternal(System.Object,Akka.Actor.IActorRef)":"Akka.Event.StandardOutLogger.yml","Akka.Event.StandardOutLogger.DebugColor":"Akka.Event.StandardOutLogger.yml","Akka.Event.StandardOutLogger.InfoColor":"Akka.Event.StandardOutLogger.yml","Akka.Event.StandardOutLogger.WarningColor":"Akka.Event.StandardOutLogger.yml","Akka.Event.StandardOutLogger.ErrorColor":"Akka.Event.StandardOutLogger.yml","Akka.Event.StandardOutLogger.UseColors":"Akka.Event.StandardOutLogger.yml","Akka.Event.StandardOutLogger.PrintLogEvent(Akka.Event.LogEvent)":"Akka.Event.StandardOutLogger.yml","Akka.Event.Subscription`2":"Akka.Event.Subscription-2.yml","Akka.Event.Subscription`2.#ctor(`0,System.Collections.Generic.IEnumerable{`1})":"Akka.Event.Subscription-2.yml","Akka.Event.Subscription`2.#ctor(`0)":"Akka.Event.Subscription-2.yml","Akka.Event.Subscription`2.Subscriber":"Akka.Event.Subscription-2.yml","Akka.Event.Subscription`2.Unsubscriptions":"Akka.Event.Subscription-2.yml","Akka.Event.TraceLogger":"Akka.Event.TraceLogger.yml","Akka.Event.TraceLogger.OnReceive(System.Object)":"Akka.Event.TraceLogger.yml","Akka.Event.UnhandledMessage":"Akka.Event.UnhandledMessage.yml","Akka.Event.UnhandledMessage.#ctor(System.Object,Akka.Actor.IActorRef,Akka.Actor.IActorRef)":"Akka.Event.UnhandledMessage.yml","Akka.Event.UnhandledMessage.Message":"Akka.Event.UnhandledMessage.yml","Akka.Event.UnhandledMessage.Sender":"Akka.Event.UnhandledMessage.yml","Akka.Event.UnhandledMessage.Recipient":"Akka.Event.UnhandledMessage.yml","Akka.Event.Warning":"Akka.Event.Warning.yml","Akka.Event.Warning.#ctor(System.String,System.Type,System.Object)":"Akka.Event.Warning.yml","Akka.Event.Warning.LogLevel":"Akka.Event.Warning.yml","Akka.Pattern":"Akka.Pattern.yml","Akka.Pattern.BackoffSupervisor":"Akka.Pattern.BackoffSupervisor.yml","Akka.Pattern.BackoffSupervisor.#ctor(Akka.Actor.Props,System.String,System.TimeSpan,System.TimeSpan,System.Double)":"Akka.Pattern.BackoffSupervisor.yml","Akka.Pattern.BackoffSupervisor.PreStart":"Akka.Pattern.BackoffSupervisor.yml","Akka.Pattern.BackoffSupervisor.OnReceive(System.Object)":"Akka.Pattern.BackoffSupervisor.yml","Akka.Pattern.BackoffSupervisor.GetCurrentChild":"Akka.Pattern.BackoffSupervisor.GetCurrentChild.yml","Akka.Pattern.BackoffSupervisor.GetCurrentChild.Instance":"Akka.Pattern.BackoffSupervisor.GetCurrentChild.yml","Akka.Pattern.BackoffSupervisor.CurrentChild":"Akka.Pattern.BackoffSupervisor.CurrentChild.yml","Akka.Pattern.BackoffSupervisor.CurrentChild.Ref":"Akka.Pattern.BackoffSupervisor.CurrentChild.yml","Akka.Pattern.BackoffSupervisor.CurrentChild.#ctor(Akka.Actor.IActorRef)":"Akka.Pattern.BackoffSupervisor.CurrentChild.yml","Akka.Pattern.BackoffSupervisor.StartChild":"Akka.Pattern.BackoffSupervisor.StartChild.yml","Akka.Pattern.BackoffSupervisor.StartChild.Instance":"Akka.Pattern.BackoffSupervisor.StartChild.yml","Akka.Pattern.BackoffSupervisor.ResetRestartCount":"Akka.Pattern.BackoffSupervisor.ResetRestartCount.yml","Akka.Pattern.BackoffSupervisor.ResetRestartCount.Current":"Akka.Pattern.BackoffSupervisor.ResetRestartCount.yml","Akka.Pattern.BackoffSupervisor.ResetRestartCount.#ctor(System.Int32)":"Akka.Pattern.BackoffSupervisor.ResetRestartCount.yml","Akka.Pattern.CircuitBreaker":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.MaxFailures":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.CallTimeout":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.ResetTimeout":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.Create(System.Int32,System.TimeSpan,System.TimeSpan)":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.#ctor(System.Int32,System.TimeSpan,System.TimeSpan)":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.CurrentFailureCount":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.WithCircuitBreaker``1(System.Func{System.Threading.Tasks.Task{``0}})":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.WithCircuitBreaker(System.Func{System.Threading.Tasks.Task})":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.WithSyncCircuitBreaker(System.Action)":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.WithSyncCircuitBreaker``1(System.Func{``0})":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.OnOpen(System.Action)":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.OnHalfOpen(System.Action)":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.CircuitBreaker.OnClose(System.Action)":"Akka.Pattern.CircuitBreaker.yml","Akka.Pattern.OpenCircuitException":"Akka.Pattern.OpenCircuitException.yml","Akka.Pattern.OpenCircuitException.#ctor":"Akka.Pattern.OpenCircuitException.yml","Akka.Pattern.OpenCircuitException.#ctor(System.String)":"Akka.Pattern.OpenCircuitException.yml","Akka.Pattern.OpenCircuitException.#ctor(System.String,System.Exception)":"Akka.Pattern.OpenCircuitException.yml","Akka.Pattern.OpenCircuitException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Pattern.OpenCircuitException.yml","Akka.Pattern.IllegalStateException":"Akka.Pattern.IllegalStateException.yml","Akka.Pattern.IllegalStateException.#ctor(System.String)":"Akka.Pattern.IllegalStateException.yml","Akka.Pattern.IllegalStateException.#ctor(System.String,System.Exception)":"Akka.Pattern.IllegalStateException.yml","Akka.Pattern.IllegalStateException.#ctor(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext)":"Akka.Pattern.IllegalStateException.yml","Akka.IO":"Akka.IO.yml","Akka.IO.DatagramChannel":"Akka.IO.DatagramChannel.yml","Akka.IO.DatagramChannel.Open":"Akka.IO.DatagramChannel.yml","Akka.IO.DatagramChannel.IsOpen":"Akka.IO.DatagramChannel.yml","Akka.IO.DatagramChannel.Send(Akka.IO.ByteBuffer,System.Net.EndPoint)":"Akka.IO.DatagramChannel.yml","Akka.IO.DatagramChannel.Receive(Akka.IO.ByteBuffer)":"Akka.IO.DatagramChannel.yml","Akka.IO.DnsBase":"Akka.IO.DnsBase.yml","Akka.IO.DnsBase.Cached(System.String)":"Akka.IO.DnsBase.yml","Akka.IO.DnsBase.Resolve(System.String,Akka.Actor.ActorSystem,Akka.Actor.IActorRef)":"Akka.IO.DnsBase.yml","Akka.IO.Dns":"Akka.IO.Dns.yml","Akka.IO.Dns.Instance":"Akka.IO.Dns.yml","Akka.IO.Dns.Cached(System.String,Akka.Actor.ActorSystem)":"Akka.IO.Dns.yml","Akka.IO.Dns.ResolveName(System.String,Akka.Actor.ActorSystem,Akka.Actor.IActorRef)":"Akka.IO.Dns.yml","Akka.IO.Dns.CreateExtension(Akka.Actor.ExtendedActorSystem)":"Akka.IO.Dns.yml","Akka.IO.Dns.Command":"Akka.IO.Dns.Command.yml","Akka.IO.Dns.Resolve":"Akka.IO.Dns.Resolve.yml","Akka.IO.Dns.Resolve.#ctor(System.String)":"Akka.IO.Dns.Resolve.yml","Akka.IO.Dns.Resolve.ConsistentHashKey":"Akka.IO.Dns.Resolve.yml","Akka.IO.Dns.Resolve.Name":"Akka.IO.Dns.Resolve.yml","Akka.IO.Dns.Resolved":"Akka.IO.Dns.Resolved.yml","Akka.IO.Dns.Resolved.#ctor(System.String,System.Collections.Generic.IEnumerable{System.Net.IPAddress},System.Collections.Generic.IEnumerable{System.Net.IPAddress})":"Akka.IO.Dns.Resolved.yml","Akka.IO.Dns.Resolved.Name":"Akka.IO.Dns.Resolved.yml","Akka.IO.Dns.Resolved.Ipv4":"Akka.IO.Dns.Resolved.yml","Akka.IO.Dns.Resolved.Ipv6":"Akka.IO.Dns.Resolved.yml","Akka.IO.Dns.Resolved.Addr":"Akka.IO.Dns.Resolved.yml","Akka.IO.Dns.Resolved.Create(System.String,System.Collections.Generic.IEnumerable{System.Net.IPAddress})":"Akka.IO.Dns.Resolved.yml","Akka.IO.DnsExt":"Akka.IO.DnsExt.yml","Akka.IO.DnsExt.#ctor(Akka.Actor.ExtendedActorSystem)":"Akka.IO.DnsExt.yml","Akka.IO.DnsExt.Manager":"Akka.IO.DnsExt.yml","Akka.IO.DnsExt.GetResolver":"Akka.IO.DnsExt.yml","Akka.IO.DnsExt.Settings":"Akka.IO.DnsExt.yml","Akka.IO.DnsExt.Cache":"Akka.IO.DnsExt.yml","Akka.IO.DnsExt.Provider":"Akka.IO.DnsExt.yml","Akka.IO.DnsExt.DnsSettings":"Akka.IO.DnsExt.DnsSettings.yml","Akka.IO.DnsExt.DnsSettings.#ctor(Akka.Configuration.Config)":"Akka.IO.DnsExt.DnsSettings.yml","Akka.IO.DnsExt.DnsSettings.Dispatcher":"Akka.IO.DnsExt.DnsSettings.yml","Akka.IO.DnsExt.DnsSettings.Resolver":"Akka.IO.DnsExt.DnsSettings.yml","Akka.IO.DnsExt.DnsSettings.ResolverConfig":"Akka.IO.DnsExt.DnsSettings.yml","Akka.IO.DnsExt.DnsSettings.ProviderObjectName":"Akka.IO.DnsExt.DnsSettings.yml","Akka.IO.IDnsProvider":"Akka.IO.IDnsProvider.yml","Akka.IO.IDnsProvider.Cache":"Akka.IO.IDnsProvider.yml","Akka.IO.IDnsProvider.ActorClass":"Akka.IO.IDnsProvider.yml","Akka.IO.IDnsProvider.ManagerClass":"Akka.IO.IDnsProvider.yml","Akka.IO.InetAddressDnsProvider":"Akka.IO.InetAddressDnsProvider.yml","Akka.IO.InetAddressDnsProvider.Cache":"Akka.IO.InetAddressDnsProvider.yml","Akka.IO.InetAddressDnsProvider.ActorClass":"Akka.IO.InetAddressDnsProvider.yml","Akka.IO.InetAddressDnsProvider.ManagerClass":"Akka.IO.InetAddressDnsProvider.yml","Akka.IO.InetAddressDnsResolver":"Akka.IO.InetAddressDnsResolver.yml","Akka.IO.InetAddressDnsResolver.#ctor(Akka.IO.SimpleDnsCache,Akka.Configuration.Config)":"Akka.IO.InetAddressDnsResolver.yml","Akka.IO.InetAddressDnsResolver.Receive(System.Object)":"Akka.IO.InetAddressDnsResolver.yml","Akka.IO.SimpleDnsCache":"Akka.IO.SimpleDnsCache.yml","Akka.IO.SimpleDnsCache.#ctor":"Akka.IO.SimpleDnsCache.yml","Akka.IO.SimpleDnsCache.Cached(System.String)":"Akka.IO.SimpleDnsCache.yml","Akka.IO.SimpleDnsCache.Clock":"Akka.IO.SimpleDnsCache.yml","Akka.IO.SimpleDnsCache.CleanUp":"Akka.IO.SimpleDnsCache.yml","Akka.IO.SimpleDnsManager":"Akka.IO.SimpleDnsManager.yml","Akka.IO.SimpleDnsManager.#ctor(Akka.IO.DnsExt)":"Akka.IO.SimpleDnsManager.yml","Akka.IO.SimpleDnsManager.Receive(System.Object)":"Akka.IO.SimpleDnsManager.yml","Akka.IO.SimpleDnsManager.PostStop":"Akka.IO.SimpleDnsManager.yml","Akka.IO.Udp":"Akka.IO.Udp.yml","Akka.IO.Udp.Instance":"Akka.IO.Udp.yml","Akka.IO.Udp.Manager(Akka.Actor.ActorSystem)":"Akka.IO.Udp.yml","Akka.IO.Udp.CreateExtension(Akka.Actor.ExtendedActorSystem)":"Akka.IO.Udp.yml","Akka.IO.Udp.Message":"Akka.IO.Udp.Message.yml","Akka.IO.Udp.Command":"Akka.IO.Udp.Command.yml","Akka.IO.Udp.Command.FailureMessage":"Akka.IO.Udp.Command.yml","Akka.IO.Udp.NoAck":"Akka.IO.Udp.NoAck.yml","Akka.IO.Udp.NoAck.Instance":"Akka.IO.Udp.NoAck.yml","Akka.IO.Udp.NoAck.#ctor(System.Object)":"Akka.IO.Udp.NoAck.yml","Akka.IO.Udp.NoAck.Token":"Akka.IO.Udp.NoAck.yml","Akka.IO.Udp.Send":"Akka.IO.Udp.Send.yml","Akka.IO.Udp.Send.#ctor(Akka.IO.ByteString,System.Net.EndPoint,Akka.IO.Udp.Event)":"Akka.IO.Udp.Send.yml","Akka.IO.Udp.Send.Payload":"Akka.IO.Udp.Send.yml","Akka.IO.Udp.Send.Target":"Akka.IO.Udp.Send.yml","Akka.IO.Udp.Send.Ack":"Akka.IO.Udp.Send.yml","Akka.IO.Udp.Send.WantsAck":"Akka.IO.Udp.Send.yml","Akka.IO.Udp.Send.Create(Akka.IO.ByteString,System.Net.EndPoint)":"Akka.IO.Udp.Send.yml","Akka.IO.Udp.Bind":"Akka.IO.Udp.Bind.yml","Akka.IO.Udp.Bind.#ctor(Akka.Actor.IActorRef,System.Net.EndPoint,System.Collections.Generic.IEnumerable{Akka.IO.Inet.SocketOption})":"Akka.IO.Udp.Bind.yml","Akka.IO.Udp.Bind.Handler":"Akka.IO.Udp.Bind.yml","Akka.IO.Udp.Bind.LocalAddress":"Akka.IO.Udp.Bind.yml","Akka.IO.Udp.Bind.Options":"Akka.IO.Udp.Bind.yml","Akka.IO.Udp.Unbind":"Akka.IO.Udp.Unbind.yml","Akka.IO.Udp.Unbind.Instance":"Akka.IO.Udp.Unbind.yml","Akka.IO.Udp.SimpleSender":"Akka.IO.Udp.SimpleSender.yml","Akka.IO.Udp.SimpleSender.Instance":"Akka.IO.Udp.SimpleSender.yml","Akka.IO.Udp.SimpleSender.#ctor(System.Collections.Generic.IEnumerable{Akka.IO.Inet.SocketOption})":"Akka.IO.Udp.SimpleSender.yml","Akka.IO.Udp.SimpleSender.Options":"Akka.IO.Udp.SimpleSender.yml","Akka.IO.Udp.SuspendReading":"Akka.IO.Udp.SuspendReading.yml","Akka.IO.Udp.SuspendReading.Instance":"Akka.IO.Udp.SuspendReading.yml","Akka.IO.Udp.ResumeReading":"Akka.IO.Udp.ResumeReading.yml","Akka.IO.Udp.ResumeReading.Instance":"Akka.IO.Udp.ResumeReading.yml","Akka.IO.Udp.Event":"Akka.IO.Udp.Event.yml","Akka.IO.Udp.Received":"Akka.IO.Udp.Received.yml","Akka.IO.Udp.Received.#ctor(Akka.IO.ByteString,System.Net.EndPoint)":"Akka.IO.Udp.Received.yml","Akka.IO.Udp.Received.Data":"Akka.IO.Udp.Received.yml","Akka.IO.Udp.Received.Sender":"Akka.IO.Udp.Received.yml","Akka.IO.Udp.CommandFailed":"Akka.IO.Udp.CommandFailed.yml","Akka.IO.Udp.CommandFailed.#ctor(Akka.IO.Udp.Command)":"Akka.IO.Udp.CommandFailed.yml","Akka.IO.Udp.CommandFailed.Cmd":"Akka.IO.Udp.CommandFailed.yml","Akka.IO.Udp.Bound":"Akka.IO.Udp.Bound.yml","Akka.IO.Udp.Bound.#ctor(System.Net.EndPoint)":"Akka.IO.Udp.Bound.yml","Akka.IO.Udp.Bound.LocalAddress":"Akka.IO.Udp.Bound.yml","Akka.IO.Udp.SimpleSenderReady":"Akka.IO.Udp.SimpleSenderReady.yml","Akka.IO.Udp.SimpleSenderReady.Instance":"Akka.IO.Udp.SimpleSenderReady.yml","Akka.IO.Udp.Unbound":"Akka.IO.Udp.Unbound.yml","Akka.IO.Udp.Unbound.Instance":"Akka.IO.Udp.Unbound.yml","Akka.IO.Udp.SO":"Akka.IO.Udp.SO.yml","Akka.IO.Udp.SO.Broadcast":"Akka.IO.Udp.SO.Broadcast.yml","Akka.IO.Udp.SO.Broadcast.#ctor(System.Boolean)":"Akka.IO.Udp.SO.Broadcast.yml","Akka.IO.Udp.SO.Broadcast.On":"Akka.IO.Udp.SO.Broadcast.yml","Akka.IO.Udp.SO.Broadcast.BeforeDatagramBind(System.Net.Sockets.Socket)":"Akka.IO.Udp.SO.Broadcast.yml","Akka.IO.UdpExt":"Akka.IO.UdpExt.yml","Akka.IO.UdpExt.#ctor(Akka.Actor.ExtendedActorSystem)":"Akka.IO.UdpExt.yml","Akka.IO.UdpExt.Manager":"Akka.IO.UdpExt.yml","Akka.IO.UdpExtensions":"Akka.IO.UdpExtensions.yml","Akka.IO.UdpExtensions.Udp(Akka.Actor.ActorSystem)":"Akka.IO.UdpExtensions.yml","Akka.IO.UdpConnected":"Akka.IO.UdpConnected.yml","Akka.IO.UdpConnected.Instance":"Akka.IO.UdpConnected.yml","Akka.IO.UdpConnected.CreateExtension(Akka.Actor.ExtendedActorSystem)":"Akka.IO.UdpConnected.yml","Akka.IO.UdpConnected.Message":"Akka.IO.UdpConnected.Message.yml","Akka.IO.UdpConnected.Command":"Akka.IO.UdpConnected.Command.yml","Akka.IO.UdpConnected.Command.#ctor":"Akka.IO.UdpConnected.Command.yml","Akka.IO.UdpConnected.Command.FailureMessage":"Akka.IO.UdpConnected.Command.yml","Akka.IO.UdpConnected.NoAck":"Akka.IO.UdpConnected.NoAck.yml","Akka.IO.UdpConnected.NoAck.Instance":"Akka.IO.UdpConnected.NoAck.yml","Akka.IO.UdpConnected.NoAck.#ctor(System.Object)":"Akka.IO.UdpConnected.NoAck.yml","Akka.IO.UdpConnected.NoAck.Token":"Akka.IO.UdpConnected.NoAck.yml","Akka.IO.UdpConnected.Send":"Akka.IO.UdpConnected.Send.yml","Akka.IO.UdpConnected.Send.#ctor(Akka.IO.ByteString,System.Object)":"Akka.IO.UdpConnected.Send.yml","Akka.IO.UdpConnected.Send.Payload":"Akka.IO.UdpConnected.Send.yml","Akka.IO.UdpConnected.Send.Ack":"Akka.IO.UdpConnected.Send.yml","Akka.IO.UdpConnected.Send.WantsAck":"Akka.IO.UdpConnected.Send.yml","Akka.IO.UdpConnected.Send.Create(Akka.IO.ByteString)":"Akka.IO.UdpConnected.Send.yml","Akka.IO.UdpConnected.Connect":"Akka.IO.UdpConnected.Connect.yml","Akka.IO.UdpConnected.Connect.#ctor(Akka.Actor.IActorRef,System.Net.EndPoint,System.Net.EndPoint,System.Collections.Generic.IEnumerable{Akka.IO.Inet.SocketOption})":"Akka.IO.UdpConnected.Connect.yml","Akka.IO.UdpConnected.Connect.Handler":"Akka.IO.UdpConnected.Connect.yml","Akka.IO.UdpConnected.Connect.RemoteAddress":"Akka.IO.UdpConnected.Connect.yml","Akka.IO.UdpConnected.Connect.LocalAddress":"Akka.IO.UdpConnected.Connect.yml","Akka.IO.UdpConnected.Connect.Options":"Akka.IO.UdpConnected.Connect.yml","Akka.IO.UdpConnected.Disconnect":"Akka.IO.UdpConnected.Disconnect.yml","Akka.IO.UdpConnected.Disconnect.Instance":"Akka.IO.UdpConnected.Disconnect.yml","Akka.IO.UdpConnected.SuspendReading":"Akka.IO.UdpConnected.SuspendReading.yml","Akka.IO.UdpConnected.SuspendReading.Instance":"Akka.IO.UdpConnected.SuspendReading.yml","Akka.IO.UdpConnected.ResumeReading":"Akka.IO.UdpConnected.ResumeReading.yml","Akka.IO.UdpConnected.ResumeReading.Instance":"Akka.IO.UdpConnected.ResumeReading.yml","Akka.IO.UdpConnected.Event":"Akka.IO.UdpConnected.Event.yml","Akka.IO.UdpConnected.Received":"Akka.IO.UdpConnected.Received.yml","Akka.IO.UdpConnected.Received.#ctor(Akka.IO.ByteString)":"Akka.IO.UdpConnected.Received.yml","Akka.IO.UdpConnected.Received.Data":"Akka.IO.UdpConnected.Received.yml","Akka.IO.UdpConnected.CommandFailed":"Akka.IO.UdpConnected.CommandFailed.yml","Akka.IO.UdpConnected.CommandFailed.#ctor(Akka.IO.UdpConnected.Command)":"Akka.IO.UdpConnected.CommandFailed.yml","Akka.IO.UdpConnected.CommandFailed.Cmd":"Akka.IO.UdpConnected.CommandFailed.yml","Akka.IO.UdpConnected.Connected":"Akka.IO.UdpConnected.Connected.yml","Akka.IO.UdpConnected.Connected.Instance":"Akka.IO.UdpConnected.Connected.yml","Akka.IO.UdpConnected.Disconnected":"Akka.IO.UdpConnected.Disconnected.yml","Akka.IO.UdpConnected.Disconnected.Instance":"Akka.IO.UdpConnected.Disconnected.yml","Akka.IO.UdpConnectedExt":"Akka.IO.UdpConnectedExt.yml","Akka.IO.UdpConnectedExt.#ctor(Akka.Actor.ExtendedActorSystem)":"Akka.IO.UdpConnectedExt.yml","Akka.IO.UdpConnectedExt.Manager":"Akka.IO.UdpConnectedExt.yml","Akka.IO.ByteBuffer":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.#ctor(System.Byte[])":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.#ctor(System.Byte[],System.Int32,System.Int32)":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Clear":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Limit(System.Int32)":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Flip":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.HasRemaining":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Remaining":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Array":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Put(System.Byte[])":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Wrap(System.Byte[],System.Int32,System.Int32)":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Wrap(System.Byte[])":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Allocate(System.Int32)":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Order(Akka.IO.ByteOrder)":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Put(System.Byte[],System.Int32,System.Int32)":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Get(System.Byte[],System.Int32,System.Int32)":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Get(System.Byte[])":"Akka.IO.ByteBuffer.yml","Akka.IO.ByteBuffer.Put(Akka.IO.ByteBuffer,System.Int32)":"Akka.IO.ByteBuffer.yml","Akka.IO.IBufferPool":"Akka.IO.IBufferPool.yml","Akka.IO.IBufferPool.Acquire":"Akka.IO.IBufferPool.yml","Akka.IO.IBufferPool.Release(Akka.IO.ByteBuffer)":"Akka.IO.IBufferPool.yml","Akka.IO.Inet":"Akka.IO.Inet.yml","Akka.IO.Inet.SocketOption":"Akka.IO.Inet.SocketOption.yml","Akka.IO.Inet.SocketOption.BeforeDatagramBind(System.Net.Sockets.Socket)":"Akka.IO.Inet.SocketOption.yml","Akka.IO.Inet.SocketOption.BeforeServerSocketBind(System.Net.Sockets.Socket)":"Akka.IO.Inet.SocketOption.yml","Akka.IO.Inet.SocketOption.BeforeConnect(System.Net.Sockets.Socket)":"Akka.IO.Inet.SocketOption.yml","Akka.IO.Inet.SocketOption.AfterConnect(System.Net.Sockets.Socket)":"Akka.IO.Inet.SocketOption.yml","Akka.IO.Inet.AbstractSocketOption":"Akka.IO.Inet.AbstractSocketOption.yml","Akka.IO.Inet.SocketOptionV2":"Akka.IO.Inet.SocketOptionV2.yml","Akka.IO.Inet.SocketOptionV2.AfterBind(System.Net.Sockets.Socket)":"Akka.IO.Inet.SocketOptionV2.yml","Akka.IO.Inet.AbstractSocketOptionV2":"Akka.IO.Inet.AbstractSocketOptionV2.yml","Akka.IO.Inet.DatagramChannelCreator":"Akka.IO.Inet.DatagramChannelCreator.yml","Akka.IO.Inet.DatagramChannelCreator.Create":"Akka.IO.Inet.DatagramChannelCreator.yml","Akka.IO.Inet.SO":"Akka.IO.Inet.SO.yml","Akka.IO.Inet.SO.ReceiveBufferSize":"Akka.IO.Inet.SO.ReceiveBufferSize.yml","Akka.IO.Inet.SO.ReceiveBufferSize.#ctor(System.Int32)":"Akka.IO.Inet.SO.ReceiveBufferSize.yml","Akka.IO.Inet.SO.ReceiveBufferSize.BeforeServerSocketBind(System.Net.Sockets.Socket)":"Akka.IO.Inet.SO.ReceiveBufferSize.yml","Akka.IO.Inet.SO.ReceiveBufferSize.BeforeDatagramBind(System.Net.Sockets.Socket)":"Akka.IO.Inet.SO.ReceiveBufferSize.yml","Akka.IO.Inet.SO.ReceiveBufferSize.BeforeConnect(System.Net.Sockets.Socket)":"Akka.IO.Inet.SO.ReceiveBufferSize.yml","Akka.IO.Inet.SO.ReuseAddress":"Akka.IO.Inet.SO.ReuseAddress.yml","Akka.IO.Inet.SO.ReuseAddress.#ctor(System.Boolean)":"Akka.IO.Inet.SO.ReuseAddress.yml","Akka.IO.Inet.SO.ReuseAddress.BeforeServerSocketBind(System.Net.Sockets.Socket)":"Akka.IO.Inet.SO.ReuseAddress.yml","Akka.IO.Inet.SO.ReuseAddress.BeforeDatagramBind(System.Net.Sockets.Socket)":"Akka.IO.Inet.SO.ReuseAddress.yml","Akka.IO.Inet.SO.ReuseAddress.BeforeConnect(System.Net.Sockets.Socket)":"Akka.IO.Inet.SO.ReuseAddress.yml","Akka.IO.Inet.SO.SendBufferSize":"Akka.IO.Inet.SO.SendBufferSize.yml","Akka.IO.Inet.SO.SendBufferSize.#ctor(System.Int32)":"Akka.IO.Inet.SO.SendBufferSize.yml","Akka.IO.Inet.SO.SendBufferSize.AfterConnect(System.Net.Sockets.Socket)":"Akka.IO.Inet.SO.SendBufferSize.yml","Akka.IO.Inet.SO.TrafficClass":"Akka.IO.Inet.SO.TrafficClass.yml","Akka.IO.Inet.SO.TrafficClass.#ctor(System.Int32)":"Akka.IO.Inet.SO.TrafficClass.yml","Akka.IO.Inet.SO.TrafficClass.AfterConnect(System.Net.Sockets.Socket)":"Akka.IO.Inet.SO.TrafficClass.yml","Akka.IO.Inet.SoForwarders":"Akka.IO.Inet.SoForwarders.yml","Akka.IO.IOExtension":"Akka.IO.IOExtension.yml","Akka.IO.IOExtension.Manager":"Akka.IO.IOExtension.yml","Akka.IO.SelectionHandlerSettings":"Akka.IO.SelectionHandlerSettings.yml","Akka.IO.SelectionHandlerSettings.#ctor(Akka.Configuration.Config)":"Akka.IO.SelectionHandlerSettings.yml","Akka.IO.SelectionHandlerSettings.MaxChannels":"Akka.IO.SelectionHandlerSettings.yml","Akka.IO.SelectionHandlerSettings.SelectorAssociationRetries":"Akka.IO.SelectionHandlerSettings.yml","Akka.IO.SelectionHandlerSettings.SelectorDispatcher":"Akka.IO.SelectionHandlerSettings.yml","Akka.IO.SelectionHandlerSettings.WorkerDispatcher":"Akka.IO.SelectionHandlerSettings.yml","Akka.IO.SelectionHandlerSettings.TraceLogging":"Akka.IO.SelectionHandlerSettings.yml","Akka.IO.SelectionHandlerSettings.MaxChannelsPerSelector":"Akka.IO.SelectionHandlerSettings.yml","Akka.IO.SocketAsyncEventArgsPool":"Akka.IO.SocketAsyncEventArgsPool.yml","Akka.IO.SocketAsyncEventArgsPool.#ctor(System.Int32,System.Action{System.Net.Sockets.SocketAsyncEventArgs})":"Akka.IO.SocketAsyncEventArgsPool.yml","Akka.IO.SocketAsyncEventArgsPool.BufferSize":"Akka.IO.SocketAsyncEventArgsPool.yml","Akka.IO.SocketAsyncEventArgsPool.Request(System.Object)":"Akka.IO.SocketAsyncEventArgsPool.yml","Akka.IO.SocketAsyncEventArgsPool.Return(System.Net.Sockets.SocketAsyncEventArgs)":"Akka.IO.SocketAsyncEventArgsPool.yml","Akka.IO.SocketChannel":"Akka.IO.SocketChannel.yml","Akka.IO.SocketChannel.#ctor(System.Net.Sockets.Socket)":"Akka.IO.SocketChannel.yml","Akka.IO.SocketChannel.Open":"Akka.IO.SocketChannel.yml","Akka.IO.SocketChannel.ConfigureBlocking(System.Boolean)":"Akka.IO.SocketChannel.yml","Akka.IO.SocketChannel.Socket":"Akka.IO.SocketChannel.yml","Akka.IO.SocketChannel.Register(Akka.Actor.IActorRef,System.Nullable{System.Net.Sockets.SocketAsyncOperation})":"Akka.IO.SocketChannel.yml","Akka.IO.SocketChannel.IsOpen":"Akka.IO.SocketChannel.yml","Akka.IO.SocketChannel.Connect(System.Net.EndPoint)":"Akka.IO.SocketChannel.yml","Akka.IO.SocketChannel.FinishConnect":"Akka.IO.SocketChannel.yml","Akka.IO.SocketChannel.Accept":"Akka.IO.SocketChannel.yml","Akka.IO.SocketChannel.Read(Akka.IO.ByteBuffer)":"Akka.IO.SocketChannel.yml","Akka.IO.SocketChannel.Write(Akka.IO.ByteBuffer)":"Akka.IO.SocketChannel.yml","Akka.IO.SocketChannel.Close":"Akka.IO.SocketChannel.yml","Akka.IO.Tcp":"Akka.IO.Tcp.yml","Akka.IO.Tcp.Instance":"Akka.IO.Tcp.yml","Akka.IO.Tcp.Manager(Akka.Actor.ActorSystem)":"Akka.IO.Tcp.yml","Akka.IO.Tcp.CreateExtension(Akka.Actor.ExtendedActorSystem)":"Akka.IO.Tcp.yml","Akka.IO.Tcp.Message":"Akka.IO.Tcp.Message.yml","Akka.IO.Tcp.Command":"Akka.IO.Tcp.Command.yml","Akka.IO.Tcp.Command.#ctor":"Akka.IO.Tcp.Command.yml","Akka.IO.Tcp.Command.FailureMessage":"Akka.IO.Tcp.Command.yml","Akka.IO.Tcp.Connect":"Akka.IO.Tcp.Connect.yml","Akka.IO.Tcp.Connect.#ctor(System.Net.EndPoint,System.Net.EndPoint,System.Collections.Generic.IEnumerable{Akka.IO.Inet.SocketOption},System.Nullable{System.TimeSpan},System.Boolean)":"Akka.IO.Tcp.Connect.yml","Akka.IO.Tcp.Connect.RemoteAddress":"Akka.IO.Tcp.Connect.yml","Akka.IO.Tcp.Connect.LocalAddress":"Akka.IO.Tcp.Connect.yml","Akka.IO.Tcp.Connect.Options":"Akka.IO.Tcp.Connect.yml","Akka.IO.Tcp.Connect.Timeout":"Akka.IO.Tcp.Connect.yml","Akka.IO.Tcp.Connect.PullMode":"Akka.IO.Tcp.Connect.yml","Akka.IO.Tcp.Bind":"Akka.IO.Tcp.Bind.yml","Akka.IO.Tcp.Bind.#ctor(Akka.Actor.IActorRef,System.Net.EndPoint,System.Int32,System.Collections.Generic.IEnumerable{Akka.IO.Inet.SocketOption},System.Boolean)":"Akka.IO.Tcp.Bind.yml","Akka.IO.Tcp.Bind.Handler":"Akka.IO.Tcp.Bind.yml","Akka.IO.Tcp.Bind.LocalAddress":"Akka.IO.Tcp.Bind.yml","Akka.IO.Tcp.Bind.Backlog":"Akka.IO.Tcp.Bind.yml","Akka.IO.Tcp.Bind.Options":"Akka.IO.Tcp.Bind.yml","Akka.IO.Tcp.Bind.PullMode":"Akka.IO.Tcp.Bind.yml","Akka.IO.Tcp.Register":"Akka.IO.Tcp.Register.yml","Akka.IO.Tcp.Register.#ctor(Akka.Actor.IActorRef,System.Boolean,System.Boolean)":"Akka.IO.Tcp.Register.yml","Akka.IO.Tcp.Register.Handler":"Akka.IO.Tcp.Register.yml","Akka.IO.Tcp.Register.KeepOpenonPeerClosed":"Akka.IO.Tcp.Register.yml","Akka.IO.Tcp.Register.UseResumeWriting":"Akka.IO.Tcp.Register.yml","Akka.IO.Tcp.Unbind":"Akka.IO.Tcp.Unbind.yml","Akka.IO.Tcp.Unbind.Instance":"Akka.IO.Tcp.Unbind.yml","Akka.IO.Tcp.CloseCommand":"Akka.IO.Tcp.CloseCommand.yml","Akka.IO.Tcp.CloseCommand.Event":"Akka.IO.Tcp.CloseCommand.yml","Akka.IO.Tcp.Close":"Akka.IO.Tcp.Close.yml","Akka.IO.Tcp.Close.Instance":"Akka.IO.Tcp.Close.yml","Akka.IO.Tcp.Close.Event":"Akka.IO.Tcp.Close.yml","Akka.IO.Tcp.ConfirmedClose":"Akka.IO.Tcp.ConfirmedClose.yml","Akka.IO.Tcp.ConfirmedClose.Instance":"Akka.IO.Tcp.ConfirmedClose.yml","Akka.IO.Tcp.ConfirmedClose.Event":"Akka.IO.Tcp.ConfirmedClose.yml","Akka.IO.Tcp.Abort":"Akka.IO.Tcp.Abort.yml","Akka.IO.Tcp.Abort.Instance":"Akka.IO.Tcp.Abort.yml","Akka.IO.Tcp.Abort.Event":"Akka.IO.Tcp.Abort.yml","Akka.IO.Tcp.NoAck":"Akka.IO.Tcp.NoAck.yml","Akka.IO.Tcp.NoAck.Instance":"Akka.IO.Tcp.NoAck.yml","Akka.IO.Tcp.NoAck.#ctor(System.Object)":"Akka.IO.Tcp.NoAck.yml","Akka.IO.Tcp.NoAck.Token":"Akka.IO.Tcp.NoAck.yml","Akka.IO.Tcp.WriteCommand":"Akka.IO.Tcp.WriteCommand.yml","Akka.IO.Tcp.WriteCommand.Prepend(Akka.IO.Tcp.SimpleWriteCommand)":"Akka.IO.Tcp.WriteCommand.yml","Akka.IO.Tcp.WriteCommand.Prepend(System.Collections.Generic.IEnumerable{Akka.IO.Tcp.WriteCommand})":"Akka.IO.Tcp.WriteCommand.yml","Akka.IO.Tcp.WriteCommand.Create(System.Collections.Generic.IEnumerable{Akka.IO.Tcp.WriteCommand})":"Akka.IO.Tcp.WriteCommand.yml","Akka.IO.Tcp.WriteCommand.Create(Akka.IO.Tcp.WriteCommand[])":"Akka.IO.Tcp.WriteCommand.yml","Akka.IO.Tcp.SimpleWriteCommand":"Akka.IO.Tcp.SimpleWriteCommand.yml","Akka.IO.Tcp.SimpleWriteCommand.Ack":"Akka.IO.Tcp.SimpleWriteCommand.yml","Akka.IO.Tcp.SimpleWriteCommand.WantsAck":"Akka.IO.Tcp.SimpleWriteCommand.yml","Akka.IO.Tcp.SimpleWriteCommand.Append(Akka.IO.Tcp.WriteCommand)":"Akka.IO.Tcp.SimpleWriteCommand.yml","Akka.IO.Tcp.Write":"Akka.IO.Tcp.Write.yml","Akka.IO.Tcp.Write.Data":"Akka.IO.Tcp.Write.yml","Akka.IO.Tcp.Write.Ack":"Akka.IO.Tcp.Write.yml","Akka.IO.Tcp.Write.Create(Akka.IO.ByteString)":"Akka.IO.Tcp.Write.yml","Akka.IO.Tcp.Write.Create(Akka.IO.ByteString,Akka.IO.Tcp.Event)":"Akka.IO.Tcp.Write.yml","Akka.IO.Tcp.Write.Empty":"Akka.IO.Tcp.Write.yml","Akka.IO.Tcp.WriteFile":"Akka.IO.Tcp.WriteFile.yml","Akka.IO.Tcp.WriteFile.#ctor(System.String,System.Int64,System.Int64,Akka.IO.Tcp.Event)":"Akka.IO.Tcp.WriteFile.yml","Akka.IO.Tcp.WriteFile.FilePath":"Akka.IO.Tcp.WriteFile.yml","Akka.IO.Tcp.WriteFile.Position":"Akka.IO.Tcp.WriteFile.yml","Akka.IO.Tcp.WriteFile.Count":"Akka.IO.Tcp.WriteFile.yml","Akka.IO.Tcp.WriteFile.Ack":"Akka.IO.Tcp.WriteFile.yml","Akka.IO.Tcp.CompoundWrite":"Akka.IO.Tcp.CompoundWrite.yml","Akka.IO.Tcp.CompoundWrite.#ctor(Akka.IO.Tcp.SimpleWriteCommand,Akka.IO.Tcp.WriteCommand)":"Akka.IO.Tcp.CompoundWrite.yml","Akka.IO.Tcp.CompoundWrite.GetEnumerator":"Akka.IO.Tcp.CompoundWrite.yml","Akka.IO.Tcp.CompoundWrite.System#Collections#IEnumerable#GetEnumerator":"Akka.IO.Tcp.CompoundWrite.yml","Akka.IO.Tcp.CompoundWrite.Head":"Akka.IO.Tcp.CompoundWrite.yml","Akka.IO.Tcp.CompoundWrite.TailCommand":"Akka.IO.Tcp.CompoundWrite.yml","Akka.IO.Tcp.ResumeWriting":"Akka.IO.Tcp.ResumeWriting.yml","Akka.IO.Tcp.ResumeWriting.Instance":"Akka.IO.Tcp.ResumeWriting.yml","Akka.IO.Tcp.SuspendReading":"Akka.IO.Tcp.SuspendReading.yml","Akka.IO.Tcp.SuspendReading.Instance":"Akka.IO.Tcp.SuspendReading.yml","Akka.IO.Tcp.ResumeReading":"Akka.IO.Tcp.ResumeReading.yml","Akka.IO.Tcp.ResumeReading.Instance":"Akka.IO.Tcp.ResumeReading.yml","Akka.IO.Tcp.ResumeAccepting":"Akka.IO.Tcp.ResumeAccepting.yml","Akka.IO.Tcp.ResumeAccepting.BatchSize":"Akka.IO.Tcp.ResumeAccepting.yml","Akka.IO.Tcp.ResumeAccepting.#ctor(System.Int32)":"Akka.IO.Tcp.ResumeAccepting.yml","Akka.IO.Tcp.Event":"Akka.IO.Tcp.Event.yml","Akka.IO.Tcp.Received":"Akka.IO.Tcp.Received.yml","Akka.IO.Tcp.Received.#ctor(Akka.IO.ByteString)":"Akka.IO.Tcp.Received.yml","Akka.IO.Tcp.Received.Data":"Akka.IO.Tcp.Received.yml","Akka.IO.Tcp.Connected":"Akka.IO.Tcp.Connected.yml","Akka.IO.Tcp.Connected.#ctor(System.Net.EndPoint,System.Net.EndPoint)":"Akka.IO.Tcp.Connected.yml","Akka.IO.Tcp.Connected.RemoteAddress":"Akka.IO.Tcp.Connected.yml","Akka.IO.Tcp.Connected.LocalAddress":"Akka.IO.Tcp.Connected.yml","Akka.IO.Tcp.CommandFailed":"Akka.IO.Tcp.CommandFailed.yml","Akka.IO.Tcp.CommandFailed.#ctor(Akka.IO.Tcp.Command)":"Akka.IO.Tcp.CommandFailed.yml","Akka.IO.Tcp.CommandFailed.Cmd":"Akka.IO.Tcp.CommandFailed.yml","Akka.IO.Tcp.WritingResumed":"Akka.IO.Tcp.WritingResumed.yml","Akka.IO.Tcp.WritingResumed.Instance":"Akka.IO.Tcp.WritingResumed.yml","Akka.IO.Tcp.Bound":"Akka.IO.Tcp.Bound.yml","Akka.IO.Tcp.Bound.LocalAddress":"Akka.IO.Tcp.Bound.yml","Akka.IO.Tcp.Bound.#ctor(System.Net.EndPoint)":"Akka.IO.Tcp.Bound.yml","Akka.IO.Tcp.Unbound":"Akka.IO.Tcp.Unbound.yml","Akka.IO.Tcp.Unbound.Instance":"Akka.IO.Tcp.Unbound.yml","Akka.IO.Tcp.ConnectionClosed":"Akka.IO.Tcp.ConnectionClosed.yml","Akka.IO.Tcp.ConnectionClosed.IsAborted":"Akka.IO.Tcp.ConnectionClosed.yml","Akka.IO.Tcp.ConnectionClosed.IsConfirmed":"Akka.IO.Tcp.ConnectionClosed.yml","Akka.IO.Tcp.ConnectionClosed.IsPeerClosed":"Akka.IO.Tcp.ConnectionClosed.yml","Akka.IO.Tcp.ConnectionClosed.IsErrorClosed":"Akka.IO.Tcp.ConnectionClosed.yml","Akka.IO.Tcp.ConnectionClosed.GetErrorCause":"Akka.IO.Tcp.ConnectionClosed.yml","Akka.IO.Tcp.Closed":"Akka.IO.Tcp.Closed.yml","Akka.IO.Tcp.Closed.Instance":"Akka.IO.Tcp.Closed.yml","Akka.IO.Tcp.Aborted":"Akka.IO.Tcp.Aborted.yml","Akka.IO.Tcp.Aborted.Instance":"Akka.IO.Tcp.Aborted.yml","Akka.IO.Tcp.Aborted.IsAborted":"Akka.IO.Tcp.Aborted.yml","Akka.IO.Tcp.ConfirmedClosed":"Akka.IO.Tcp.ConfirmedClosed.yml","Akka.IO.Tcp.ConfirmedClosed.Instance":"Akka.IO.Tcp.ConfirmedClosed.yml","Akka.IO.Tcp.ConfirmedClosed.IsConfirmed":"Akka.IO.Tcp.ConfirmedClosed.yml","Akka.IO.Tcp.PeerClosed":"Akka.IO.Tcp.PeerClosed.yml","Akka.IO.Tcp.PeerClosed.Instance":"Akka.IO.Tcp.PeerClosed.yml","Akka.IO.Tcp.PeerClosed.IsPeerClosed":"Akka.IO.Tcp.PeerClosed.yml","Akka.IO.Tcp.ErrorClosed":"Akka.IO.Tcp.ErrorClosed.yml","Akka.IO.Tcp.ErrorClosed.#ctor(System.String)":"Akka.IO.Tcp.ErrorClosed.yml","Akka.IO.Tcp.ErrorClosed.IsErrorClosed":"Akka.IO.Tcp.ErrorClosed.yml","Akka.IO.Tcp.ErrorClosed.GetErrorCause":"Akka.IO.Tcp.ErrorClosed.yml","Akka.IO.TcpExt":"Akka.IO.TcpExt.yml","Akka.IO.TcpExt.#ctor(Akka.Actor.ExtendedActorSystem)":"Akka.IO.TcpExt.yml","Akka.IO.TcpExt.Manager":"Akka.IO.TcpExt.yml","Akka.IO.TcpExt.GetManager":"Akka.IO.TcpExt.yml","Akka.IO.TcpExt.Settings":"Akka.IO.TcpExt.yml","Akka.IO.TcpExt.TcpSettings":"Akka.IO.TcpExt.TcpSettings.yml","Akka.IO.TcpExt.TcpSettings.#ctor(Akka.Configuration.Config)":"Akka.IO.TcpExt.TcpSettings.yml","Akka.IO.TcpExt.TcpSettings.NrOfSelectors":"Akka.IO.TcpExt.TcpSettings.yml","Akka.IO.TcpExt.TcpSettings.BatchAcceptLimit":"Akka.IO.TcpExt.TcpSettings.yml","Akka.IO.TcpExt.TcpSettings.DirectBufferSize":"Akka.IO.TcpExt.TcpSettings.yml","Akka.IO.TcpExt.TcpSettings.MaxDirectBufferPoolSize":"Akka.IO.TcpExt.TcpSettings.yml","Akka.IO.TcpExt.TcpSettings.RegisterTimeout":"Akka.IO.TcpExt.TcpSettings.yml","Akka.IO.TcpExt.TcpSettings.ReceivedMessageSizeLimit":"Akka.IO.TcpExt.TcpSettings.yml","Akka.IO.TcpExt.TcpSettings.ManagementDispatcher":"Akka.IO.TcpExt.TcpSettings.yml","Akka.IO.TcpExt.TcpSettings.FileIODispatcher":"Akka.IO.TcpExt.TcpSettings.yml","Akka.IO.TcpExt.TcpSettings.TransferToLimit":"Akka.IO.TcpExt.TcpSettings.yml","Akka.IO.TcpExt.TcpSettings.FinishConnectRetries":"Akka.IO.TcpExt.TcpSettings.yml","Akka.IO.TcpMessage":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.Connect(System.Net.EndPoint,System.Net.EndPoint,System.Collections.Generic.IEnumerable{Akka.IO.Inet.SocketOption},System.Nullable{System.TimeSpan},System.Boolean)":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.Connect(System.Net.EndPoint)":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.Bind(Akka.Actor.IActorRef,System.Net.EndPoint,System.Int32,System.Collections.Generic.IEnumerable{Akka.IO.Inet.SocketOption},System.Boolean)":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.Bind(Akka.Actor.IActorRef,System.Net.EndPoint,System.Int32)":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.Register(Akka.Actor.IActorRef,System.Boolean,System.Boolean)":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.Unbind":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.Close":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.ConfirmedClose":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.Abort":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.NoAck(System.Object)":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.Write(Akka.IO.ByteString,Akka.IO.Tcp.Event)":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.ResumeWriting":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.SuspendReading":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.ResumeReading":"Akka.IO.TcpMessage.yml","Akka.IO.TcpMessage.ResumeAccepting(System.Int32)":"Akka.IO.TcpMessage.yml","Akka.IO.TcpExtensions":"Akka.IO.TcpExtensions.yml","Akka.IO.TcpExtensions.Tcp(Akka.Actor.ActorSystem)":"Akka.IO.TcpExtensions.yml","Akka.IO.ByteString":"Akka.IO.ByteString.yml","Akka.IO.ByteString.FromArray(System.Byte[])":"Akka.IO.ByteString.yml","Akka.IO.ByteString.FromArray(System.Byte[],System.Int32,System.Int32)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.FromString(System.String)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.FromString(System.String,System.Text.Encoding)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.FromByteBuffer(Akka.IO.ByteBuffer)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Empty":"Akka.IO.ByteString.yml","Akka.IO.ByteString.NewBuilder":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Item(System.Int32)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.AsByteBuffer":"Akka.IO.ByteString.yml","Akka.IO.ByteString.newBuilder":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Iterator":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Head":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Tail":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Last":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Init":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Slice(System.Int32,System.Int32)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Take(System.Int32)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.TakeRight(System.Int32)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Drop(System.Int32)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.DropRight(System.Int32)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.TakeWhile(System.Func{System.Byte,System.Boolean})":"Akka.IO.ByteString.yml","Akka.IO.ByteString.DropWhile(System.Func{System.Byte,System.Boolean})":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Span(System.Func{System.Byte,System.Boolean})":"Akka.IO.ByteString.yml","Akka.IO.ByteString.SplitAt(System.Int32)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.IndexWhere(System.Func{System.Byte,System.Boolean})":"Akka.IO.ByteString.yml","Akka.IO.ByteString.IndexOf(System.Byte)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.ToArray":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Compact":"Akka.IO.ByteString.yml","Akka.IO.ByteString.IsCompact":"Akka.IO.ByteString.yml","Akka.IO.ByteString.GetEnumerator":"Akka.IO.ByteString.yml","Akka.IO.ByteString.System#Collections#IEnumerable#GetEnumerator":"Akka.IO.ByteString.yml","Akka.IO.ByteString.IsEmpty":"Akka.IO.ByteString.yml","Akka.IO.ByteString.NonEmpty":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Count":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Concat(Akka.IO.ByteString)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.DecodeString":"Akka.IO.ByteString.yml","Akka.IO.ByteString.DecodeString(System.Text.Encoding)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.op_Addition(Akka.IO.ByteString,Akka.IO.ByteString)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.CopyToBuffer(Akka.IO.ByteBuffer)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Create(Akka.IO.ByteBuffer)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Create(System.Byte[],System.Int32,System.Int32)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Create(System.Byte[])":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Equals(Akka.IO.ByteString)":"Akka.IO.ByteString.yml","Akka.IO.ByteString.Equals(System.Object)":"Akka.IO.ByteString.yml","Akka.IO.CompactByteString":"Akka.IO.CompactByteString.yml","Akka.IO.CompactByteString.FromString(System.String,System.Text.Encoding)":"Akka.IO.CompactByteString.yml","Akka.IO.CompactByteString.FromArray(System.Byte[],System.Int32,System.Int32)":"Akka.IO.CompactByteString.yml","Akka.IO.CompactByteString.IsCompact":"Akka.IO.CompactByteString.yml","Akka.IO.CompactByteString.Compact":"Akka.IO.CompactByteString.yml","Akka.IO.ByteStringBuilder":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteStringBuilder.FillArray(System.Int32)":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteStringBuilder.FillByteBuffer(System.Int32,Akka.IO.ByteOrder,System.Action{Akka.IO.ByteBuffer})":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteStringBuilder.Length":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteStringBuilder.SizeHint(System.Int32)":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteStringBuilder.Append(System.Collections.Generic.IEnumerable{System.Byte})":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteStringBuilder.PutByte(System.Byte)":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteStringBuilder.PutShort(System.Int32,Akka.IO.ByteOrder)":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteStringBuilder.PutInt(System.Int32,Akka.IO.ByteOrder)":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteStringBuilder.PutBytes(System.Byte[])":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteStringBuilder.PutBytes(System.Byte[],System.Int32,System.Int32)":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteStringBuilder.op_Addition(Akka.IO.ByteStringBuilder,System.Byte)":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteStringBuilder.Result":"Akka.IO.ByteStringBuilder.yml","Akka.IO.ByteOrder":"Akka.IO.ByteOrder.yml","Akka.IO.ByteOrder.BigEndian":"Akka.IO.ByteOrder.yml","Akka.IO.ByteOrder.LittleEndian":"Akka.IO.ByteOrder.yml","Akka.Routing":"Akka.Routing.yml","Akka.Routing.IConsistentHashable":"Akka.Routing.IConsistentHashable.yml","Akka.Routing.IConsistentHashable.ConsistentHashKey":"Akka.Routing.IConsistentHashable.yml","Akka.Routing.ConsistentHashableEnvelope":"Akka.Routing.ConsistentHashableEnvelope.yml","Akka.Routing.ConsistentHashableEnvelope.#ctor(System.Object,System.Object)":"Akka.Routing.ConsistentHashableEnvelope.yml","Akka.Routing.ConsistentHashableEnvelope.HashKey":"Akka.Routing.ConsistentHashableEnvelope.yml","Akka.Routing.ConsistentHashableEnvelope.ConsistentHashKey":"Akka.Routing.ConsistentHashableEnvelope.yml","Akka.Routing.ConsistentHashMapping":"Akka.Routing.ConsistentHashMapping.yml","Akka.Routing.ConsistentHashingRoutingLogic":"Akka.Routing.ConsistentHashingRoutingLogic.yml","Akka.Routing.ConsistentHashingRoutingLogic.#ctor(Akka.Actor.ActorSystem)":"Akka.Routing.ConsistentHashingRoutingLogic.yml","Akka.Routing.ConsistentHashingRoutingLogic.#ctor(Akka.Actor.ActorSystem,System.Int32,Akka.Routing.ConsistentHashMapping)":"Akka.Routing.ConsistentHashingRoutingLogic.yml","Akka.Routing.ConsistentHashingRoutingLogic.Select(System.Object,Akka.Routing.Routee[])":"Akka.Routing.ConsistentHashingRoutingLogic.yml","Akka.Routing.ConsistentHashingRoutingLogic.WithHashMapping(Akka.Routing.ConsistentHashMapping)":"Akka.Routing.ConsistentHashingRoutingLogic.yml","Akka.Routing.ConsistentHashingPool":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.#ctor(System.Int32)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.#ctor(Akka.Configuration.Config)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.#ctor(System.Int32,Akka.Routing.ConsistentHashMapping)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.#ctor(System.Int32,Akka.Routing.Resizer,Akka.Actor.SupervisorStrategy,System.String,System.Boolean,System.Int32,Akka.Routing.ConsistentHashMapping)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.VirtualNodesFactor":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.GetNrOfInstances(Akka.Actor.ActorSystem)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.WithSupervisorStrategy(Akka.Actor.SupervisorStrategy)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.WithResizer(Akka.Routing.Resizer)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.WithDispatcher(System.String)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.WithVirtualNodesFactor(System.Int32)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.WithHashMapping(Akka.Routing.ConsistentHashMapping)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.WithFallback(Akka.Routing.RouterConfig)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.ConsistentHashingPool.yml","Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate":"Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.NrOfInstances":"Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.UsePoolDispatcher":"Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.Resizer":"Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.SupervisorStrategy":"Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.RouterDispatcher":"Akka.Routing.ConsistentHashingPool.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHashingGroup":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.#ctor(Akka.Configuration.Config)":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.#ctor(System.String[])":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.#ctor(System.Collections.Generic.IEnumerable{System.String})":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.#ctor(System.Collections.Generic.IEnumerable{Akka.Actor.IActorRef})":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.#ctor(System.Collections.Generic.IEnumerable{System.String},Akka.Routing.ConsistentHashMapping)":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.#ctor(System.Collections.Generic.IEnumerable{System.String},System.Int32,Akka.Routing.ConsistentHashMapping,System.String)":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.VirtualNodesFactor":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.GetPaths(Akka.Actor.ActorSystem)":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.WithDispatcher(System.String)":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.WithVirtualNodesFactor(System.Int32)":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.WithHashMapping(Akka.Routing.ConsistentHashMapping)":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.WithFallback(Akka.Routing.RouterConfig)":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.ConsistentHashingGroup.yml","Akka.Routing.ConsistentHashingGroup.ConsistentHashingGroupSurrogate":"Akka.Routing.ConsistentHashingGroup.ConsistentHashingGroupSurrogate.yml","Akka.Routing.ConsistentHashingGroup.ConsistentHashingGroupSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.ConsistentHashingGroup.ConsistentHashingGroupSurrogate.yml","Akka.Routing.ConsistentHashingGroup.ConsistentHashingGroupSurrogate.Paths":"Akka.Routing.ConsistentHashingGroup.ConsistentHashingGroupSurrogate.yml","Akka.Routing.ConsistentHashingGroup.ConsistentHashingGroupSurrogate.RouterDispatcher":"Akka.Routing.ConsistentHashingGroup.ConsistentHashingGroupSurrogate.yml","Akka.Routing.SmallestMailboxRoutingLogic":"Akka.Routing.SmallestMailboxRoutingLogic.yml","Akka.Routing.SmallestMailboxRoutingLogic.#ctor":"Akka.Routing.SmallestMailboxRoutingLogic.yml","Akka.Routing.SmallestMailboxRoutingLogic.#ctor(System.Int32)":"Akka.Routing.SmallestMailboxRoutingLogic.yml","Akka.Routing.SmallestMailboxRoutingLogic.Select(System.Object,Akka.Routing.Routee[])":"Akka.Routing.SmallestMailboxRoutingLogic.yml","Akka.Routing.SmallestMailboxPool":"Akka.Routing.SmallestMailboxPool.yml","Akka.Routing.SmallestMailboxPool.#ctor(Akka.Configuration.Config)":"Akka.Routing.SmallestMailboxPool.yml","Akka.Routing.SmallestMailboxPool.#ctor(System.Int32)":"Akka.Routing.SmallestMailboxPool.yml","Akka.Routing.SmallestMailboxPool.#ctor(System.Int32,Akka.Routing.Resizer,Akka.Actor.SupervisorStrategy,System.String,System.Boolean)":"Akka.Routing.SmallestMailboxPool.yml","Akka.Routing.SmallestMailboxPool.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.SmallestMailboxPool.yml","Akka.Routing.SmallestMailboxPool.GetNrOfInstances(Akka.Actor.ActorSystem)":"Akka.Routing.SmallestMailboxPool.yml","Akka.Routing.SmallestMailboxPool.WithSupervisorStrategy(Akka.Actor.SupervisorStrategy)":"Akka.Routing.SmallestMailboxPool.yml","Akka.Routing.SmallestMailboxPool.WithResizer(Akka.Routing.Resizer)":"Akka.Routing.SmallestMailboxPool.yml","Akka.Routing.SmallestMailboxPool.WithDispatcher(System.String)":"Akka.Routing.SmallestMailboxPool.yml","Akka.Routing.SmallestMailboxPool.WithFallback(Akka.Routing.RouterConfig)":"Akka.Routing.SmallestMailboxPool.yml","Akka.Routing.SmallestMailboxPool.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.SmallestMailboxPool.yml","Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate":"Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.yml","Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.yml","Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.NrOfInstances":"Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.yml","Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.UsePoolDispatcher":"Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.yml","Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.Resizer":"Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.yml","Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.SupervisorStrategy":"Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.yml","Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.RouterDispatcher":"Akka.Routing.SmallestMailboxPool.SmallestMailboxPoolSurrogate.yml","Akka.Routing.TailChopping":"Akka.Routing.TailChopping.yml","Akka.Routing.TailChopping.#ctor(Akka.Actor.IScheduler,System.TimeSpan,System.TimeSpan)":"Akka.Routing.TailChopping.yml","Akka.Routing.TailChopping.Select(System.Object,Akka.Routing.Routee[])":"Akka.Routing.TailChopping.yml","Akka.Routing.TailChoppingPool":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.#ctor(Akka.Configuration.Config)":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.#ctor(System.Int32,System.TimeSpan,System.TimeSpan)":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.#ctor(System.Int32,Akka.Routing.Resizer,Akka.Actor.SupervisorStrategy,System.String,System.TimeSpan,System.TimeSpan,System.Boolean)":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.Within":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.Interval":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.GetNrOfInstances(Akka.Actor.ActorSystem)":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.WithSupervisorStrategy(Akka.Actor.SupervisorStrategy)":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.WithResizer(Akka.Routing.Resizer)":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.WithDispatcher(System.String)":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.WithFallback(Akka.Routing.RouterConfig)":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.TailChoppingPool.yml","Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate":"Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.yml","Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.yml","Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.Interval":"Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.yml","Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.Within":"Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.yml","Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.NrOfInstances":"Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.yml","Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.UsePoolDispatcher":"Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.yml","Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.Resizer":"Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.yml","Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.SupervisorStrategy":"Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.yml","Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.RouterDispatcher":"Akka.Routing.TailChoppingPool.TailChoppingPoolSurrogate.yml","Akka.Routing.TailChoppingGroup":"Akka.Routing.TailChoppingGroup.yml","Akka.Routing.TailChoppingGroup.#ctor(Akka.Configuration.Config)":"Akka.Routing.TailChoppingGroup.yml","Akka.Routing.TailChoppingGroup.#ctor(System.Collections.Generic.IEnumerable{System.String},System.TimeSpan,System.TimeSpan)":"Akka.Routing.TailChoppingGroup.yml","Akka.Routing.TailChoppingGroup.#ctor(System.Collections.Generic.IEnumerable{System.String},System.TimeSpan,System.TimeSpan,System.String)":"Akka.Routing.TailChoppingGroup.yml","Akka.Routing.TailChoppingGroup.Within":"Akka.Routing.TailChoppingGroup.yml","Akka.Routing.TailChoppingGroup.Interval":"Akka.Routing.TailChoppingGroup.yml","Akka.Routing.TailChoppingGroup.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.TailChoppingGroup.yml","Akka.Routing.TailChoppingGroup.GetPaths(Akka.Actor.ActorSystem)":"Akka.Routing.TailChoppingGroup.yml","Akka.Routing.TailChoppingGroup.WithDispatcher(System.String)":"Akka.Routing.TailChoppingGroup.yml","Akka.Routing.TailChoppingGroup.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.TailChoppingGroup.yml","Akka.Routing.TailChoppingGroup.TailChoppingGroupSurrogate":"Akka.Routing.TailChoppingGroup.TailChoppingGroupSurrogate.yml","Akka.Routing.TailChoppingGroup.TailChoppingGroupSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.TailChoppingGroup.TailChoppingGroupSurrogate.yml","Akka.Routing.TailChoppingGroup.TailChoppingGroupSurrogate.Paths":"Akka.Routing.TailChoppingGroup.TailChoppingGroupSurrogate.yml","Akka.Routing.TailChoppingGroup.TailChoppingGroupSurrogate.Within":"Akka.Routing.TailChoppingGroup.TailChoppingGroupSurrogate.yml","Akka.Routing.TailChoppingGroup.TailChoppingGroupSurrogate.Interval":"Akka.Routing.TailChoppingGroup.TailChoppingGroupSurrogate.yml","Akka.Routing.TailChoppingGroup.TailChoppingGroupSurrogate.RouterDispatcher":"Akka.Routing.TailChoppingGroup.TailChoppingGroupSurrogate.yml","Akka.Routing.BroadcastRoutingLogic":"Akka.Routing.BroadcastRoutingLogic.yml","Akka.Routing.BroadcastRoutingLogic.Select(System.Object,Akka.Routing.Routee[])":"Akka.Routing.BroadcastRoutingLogic.yml","Akka.Routing.BroadcastPool":"Akka.Routing.BroadcastPool.yml","Akka.Routing.BroadcastPool.#ctor(System.Int32)":"Akka.Routing.BroadcastPool.yml","Akka.Routing.BroadcastPool.#ctor(Akka.Configuration.Config)":"Akka.Routing.BroadcastPool.yml","Akka.Routing.BroadcastPool.#ctor(System.Int32,Akka.Routing.Resizer,Akka.Actor.SupervisorStrategy,System.String,System.Boolean)":"Akka.Routing.BroadcastPool.yml","Akka.Routing.BroadcastPool.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.BroadcastPool.yml","Akka.Routing.BroadcastPool.GetNrOfInstances(Akka.Actor.ActorSystem)":"Akka.Routing.BroadcastPool.yml","Akka.Routing.BroadcastPool.WithSupervisorStrategy(Akka.Actor.SupervisorStrategy)":"Akka.Routing.BroadcastPool.yml","Akka.Routing.BroadcastPool.WithResizer(Akka.Routing.Resizer)":"Akka.Routing.BroadcastPool.yml","Akka.Routing.BroadcastPool.WithDispatcher(System.String)":"Akka.Routing.BroadcastPool.yml","Akka.Routing.BroadcastPool.WithFallback(Akka.Routing.RouterConfig)":"Akka.Routing.BroadcastPool.yml","Akka.Routing.BroadcastPool.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.BroadcastPool.yml","Akka.Routing.BroadcastPool.BroadcastPoolSurrogate":"Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.yml","Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.yml","Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.NrOfInstances":"Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.yml","Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.UsePoolDispatcher":"Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.yml","Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.Resizer":"Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.yml","Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.SupervisorStrategy":"Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.yml","Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.RouterDispatcher":"Akka.Routing.BroadcastPool.BroadcastPoolSurrogate.yml","Akka.Routing.BroadcastGroup":"Akka.Routing.BroadcastGroup.yml","Akka.Routing.BroadcastGroup.#ctor(Akka.Configuration.Config)":"Akka.Routing.BroadcastGroup.yml","Akka.Routing.BroadcastGroup.#ctor(System.String[])":"Akka.Routing.BroadcastGroup.yml","Akka.Routing.BroadcastGroup.#ctor(System.Collections.Generic.IEnumerable{System.String})":"Akka.Routing.BroadcastGroup.yml","Akka.Routing.BroadcastGroup.#ctor(System.Collections.Generic.IEnumerable{Akka.Actor.IActorRef})":"Akka.Routing.BroadcastGroup.yml","Akka.Routing.BroadcastGroup.#ctor(System.Collections.Generic.IEnumerable{System.String},System.String)":"Akka.Routing.BroadcastGroup.yml","Akka.Routing.BroadcastGroup.GetPaths(Akka.Actor.ActorSystem)":"Akka.Routing.BroadcastGroup.yml","Akka.Routing.BroadcastGroup.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.BroadcastGroup.yml","Akka.Routing.BroadcastGroup.WithDispatcher(System.String)":"Akka.Routing.BroadcastGroup.yml","Akka.Routing.BroadcastGroup.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.BroadcastGroup.yml","Akka.Routing.BroadcastGroup.BroadcastGroupSurrogate":"Akka.Routing.BroadcastGroup.BroadcastGroupSurrogate.yml","Akka.Routing.BroadcastGroup.BroadcastGroupSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.BroadcastGroup.BroadcastGroupSurrogate.yml","Akka.Routing.BroadcastGroup.BroadcastGroupSurrogate.Paths":"Akka.Routing.BroadcastGroup.BroadcastGroupSurrogate.yml","Akka.Routing.BroadcastGroup.BroadcastGroupSurrogate.RouterDispatcher":"Akka.Routing.BroadcastGroup.BroadcastGroupSurrogate.yml","Akka.Routing.ConsistentHash`1":"Akka.Routing.ConsistentHash-1.yml","Akka.Routing.ConsistentHash`1.#ctor(System.Collections.Generic.SortedDictionary{System.Int32,`0},System.Int32)":"Akka.Routing.ConsistentHash-1.yml","Akka.Routing.ConsistentHash`1.Add(`0)":"Akka.Routing.ConsistentHash-1.yml","Akka.Routing.ConsistentHash`1.Remove(`0)":"Akka.Routing.ConsistentHash-1.yml","Akka.Routing.ConsistentHash`1.NodeFor(System.Byte[])":"Akka.Routing.ConsistentHash-1.yml","Akka.Routing.ConsistentHash`1.NodeFor(System.String)":"Akka.Routing.ConsistentHash-1.yml","Akka.Routing.ConsistentHash`1.IsEmpty":"Akka.Routing.ConsistentHash-1.yml","Akka.Routing.ConsistentHash`1.op_Addition(Akka.Routing.ConsistentHash{`0},`0)":"Akka.Routing.ConsistentHash-1.yml","Akka.Routing.ConsistentHash`1.op_Subtraction(Akka.Routing.ConsistentHash{`0},`0)":"Akka.Routing.ConsistentHash-1.yml","Akka.Routing.ConsistentHash`1.ConsistentHashingGroupSurrogate":"Akka.Routing.ConsistentHash-1.ConsistentHashingGroupSurrogate.yml","Akka.Routing.ConsistentHash`1.ConsistentHashingGroupSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.ConsistentHash-1.ConsistentHashingGroupSurrogate.yml","Akka.Routing.ConsistentHash`1.ConsistentHashingGroupSurrogate.Paths":"Akka.Routing.ConsistentHash-1.ConsistentHashingGroupSurrogate.yml","Akka.Routing.ConsistentHash":"Akka.Routing.ConsistentHash.yml","Akka.Routing.ConsistentHash.Create``1(System.Collections.Generic.IEnumerable{``0},System.Int32)":"Akka.Routing.ConsistentHash.yml","Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate":"Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.NrOfInstances":"Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.UsePoolDispatcher":"Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.Resizer":"Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.SupervisorStrategy":"Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.yml","Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.RouterDispatcher":"Akka.Routing.ConsistentHash.ConsistentHashingPoolSurrogate.yml","Akka.Routing.IListeners":"Akka.Routing.IListeners.yml","Akka.Routing.IListeners.Listeners":"Akka.Routing.IListeners.yml","Akka.Routing.ListenerMessage":"Akka.Routing.ListenerMessage.yml","Akka.Routing.Listen":"Akka.Routing.Listen.yml","Akka.Routing.Listen.#ctor(Akka.Actor.IActorRef)":"Akka.Routing.Listen.yml","Akka.Routing.Listen.Listener":"Akka.Routing.Listen.yml","Akka.Routing.Deafen":"Akka.Routing.Deafen.yml","Akka.Routing.Deafen.#ctor(Akka.Actor.IActorRef)":"Akka.Routing.Deafen.yml","Akka.Routing.Deafen.Listener":"Akka.Routing.Deafen.yml","Akka.Routing.WithListeners":"Akka.Routing.WithListeners.yml","Akka.Routing.WithListeners.#ctor(System.Action{Akka.Actor.IActorRef})":"Akka.Routing.WithListeners.yml","Akka.Routing.WithListeners.ListenerFunction":"Akka.Routing.WithListeners.yml","Akka.Routing.ListenerSupport":"Akka.Routing.ListenerSupport.yml","Akka.Routing.ListenerSupport.Listeners":"Akka.Routing.ListenerSupport.yml","Akka.Routing.ListenerSupport.ListenerReceive":"Akka.Routing.ListenerSupport.yml","Akka.Routing.ListenerSupport.Add(Akka.Actor.IActorRef)":"Akka.Routing.ListenerSupport.yml","Akka.Routing.ListenerSupport.Remove(Akka.Actor.IActorRef)":"Akka.Routing.ListenerSupport.yml","Akka.Routing.ListenerSupport.Gossip(System.Object)":"Akka.Routing.ListenerSupport.yml","Akka.Routing.ListenerSupport.Gossip(System.Object,Akka.Actor.IActorRef)":"Akka.Routing.ListenerSupport.yml","Akka.Routing.RandomLogic":"Akka.Routing.RandomLogic.yml","Akka.Routing.RandomLogic.Select(System.Object,Akka.Routing.Routee[])":"Akka.Routing.RandomLogic.yml","Akka.Routing.RandomPool":"Akka.Routing.RandomPool.yml","Akka.Routing.RandomPool.#ctor(Akka.Configuration.Config)":"Akka.Routing.RandomPool.yml","Akka.Routing.RandomPool.#ctor(System.Int32)":"Akka.Routing.RandomPool.yml","Akka.Routing.RandomPool.#ctor(System.Int32,Akka.Routing.Resizer,Akka.Actor.SupervisorStrategy,System.String,System.Boolean)":"Akka.Routing.RandomPool.yml","Akka.Routing.RandomPool.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.RandomPool.yml","Akka.Routing.RandomPool.GetNrOfInstances(Akka.Actor.ActorSystem)":"Akka.Routing.RandomPool.yml","Akka.Routing.RandomPool.WithSupervisorStrategy(Akka.Actor.SupervisorStrategy)":"Akka.Routing.RandomPool.yml","Akka.Routing.RandomPool.WithResizer(Akka.Routing.Resizer)":"Akka.Routing.RandomPool.yml","Akka.Routing.RandomPool.WithDispatcher(System.String)":"Akka.Routing.RandomPool.yml","Akka.Routing.RandomPool.WithFallback(Akka.Routing.RouterConfig)":"Akka.Routing.RandomPool.yml","Akka.Routing.RandomPool.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.RandomPool.yml","Akka.Routing.RandomPool.RandomPoolSurrogate":"Akka.Routing.RandomPool.RandomPoolSurrogate.yml","Akka.Routing.RandomPool.RandomPoolSurrogate.NrOfInstances":"Akka.Routing.RandomPool.RandomPoolSurrogate.yml","Akka.Routing.RandomPool.RandomPoolSurrogate.UsePoolDispatcher":"Akka.Routing.RandomPool.RandomPoolSurrogate.yml","Akka.Routing.RandomPool.RandomPoolSurrogate.Resizer":"Akka.Routing.RandomPool.RandomPoolSurrogate.yml","Akka.Routing.RandomPool.RandomPoolSurrogate.SupervisorStrategy":"Akka.Routing.RandomPool.RandomPoolSurrogate.yml","Akka.Routing.RandomPool.RandomPoolSurrogate.RouterDispatcher":"Akka.Routing.RandomPool.RandomPoolSurrogate.yml","Akka.Routing.RandomPool.RandomPoolSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.RandomPool.RandomPoolSurrogate.yml","Akka.Routing.RandomGroup":"Akka.Routing.RandomGroup.yml","Akka.Routing.RandomGroup.#ctor(Akka.Configuration.Config)":"Akka.Routing.RandomGroup.yml","Akka.Routing.RandomGroup.#ctor(System.String[])":"Akka.Routing.RandomGroup.yml","Akka.Routing.RandomGroup.#ctor(System.Collections.Generic.IEnumerable{System.String})":"Akka.Routing.RandomGroup.yml","Akka.Routing.RandomGroup.#ctor(System.Collections.Generic.IEnumerable{System.String},System.String)":"Akka.Routing.RandomGroup.yml","Akka.Routing.RandomGroup.GetPaths(Akka.Actor.ActorSystem)":"Akka.Routing.RandomGroup.yml","Akka.Routing.RandomGroup.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.RandomGroup.yml","Akka.Routing.RandomGroup.WithDispatcher(System.String)":"Akka.Routing.RandomGroup.yml","Akka.Routing.RandomGroup.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.RandomGroup.yml","Akka.Routing.RandomGroup.RandomGroupSurrogate":"Akka.Routing.RandomGroup.RandomGroupSurrogate.yml","Akka.Routing.RandomGroup.RandomGroupSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.RandomGroup.RandomGroupSurrogate.yml","Akka.Routing.RandomGroup.RandomGroupSurrogate.Paths":"Akka.Routing.RandomGroup.RandomGroupSurrogate.yml","Akka.Routing.RandomGroup.RandomGroupSurrogate.RouterDispatcher":"Akka.Routing.RandomGroup.RandomGroupSurrogate.yml","Akka.Routing.Resize":"Akka.Routing.Resize.yml","Akka.Routing.Resizer":"Akka.Routing.Resizer.yml","Akka.Routing.Resizer.IsTimeForResize(System.Int64)":"Akka.Routing.Resizer.yml","Akka.Routing.Resizer.Resize(System.Collections.Generic.IEnumerable{Akka.Routing.Routee})":"Akka.Routing.Resizer.yml","Akka.Routing.Resizer.FromConfig(Akka.Configuration.Config)":"Akka.Routing.Resizer.yml","Akka.Routing.DefaultResizer":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.#ctor(System.Int32,System.Int32,System.Int32,System.Double,System.Double,System.Double,System.Int32)":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.FromConfig(Akka.Configuration.Config)":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.IsTimeForResize(System.Int64)":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.Resize(System.Collections.Generic.IEnumerable{Akka.Routing.Routee})":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.Capacity(System.Collections.Generic.IEnumerable{Akka.Routing.Routee})":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.Pressure(System.Collections.Generic.IEnumerable{Akka.Routing.Routee})":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.Filter(System.Int32,System.Int32)":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.Rampup(System.Int32,System.Int32)":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.Backoff(System.Int32,System.Int32)":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.LowerBound":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.UpperBound":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.PressureThreshold":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.RampupRate":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.BackoffThreshold":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.BackoffRate":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.MessagesPerResize":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.Equals(Akka.Routing.DefaultResizer)":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.Equals(System.Object)":"Akka.Routing.DefaultResizer.yml","Akka.Routing.DefaultResizer.GetHashCode":"Akka.Routing.DefaultResizer.yml","Akka.Routing.RoundRobinRoutingLogic":"Akka.Routing.RoundRobinRoutingLogic.yml","Akka.Routing.RoundRobinRoutingLogic.#ctor":"Akka.Routing.RoundRobinRoutingLogic.yml","Akka.Routing.RoundRobinRoutingLogic.#ctor(System.Int32)":"Akka.Routing.RoundRobinRoutingLogic.yml","Akka.Routing.RoundRobinRoutingLogic.Select(System.Object,Akka.Routing.Routee[])":"Akka.Routing.RoundRobinRoutingLogic.yml","Akka.Routing.RoundRobinPool":"Akka.Routing.RoundRobinPool.yml","Akka.Routing.RoundRobinPool.#ctor(Akka.Configuration.Config)":"Akka.Routing.RoundRobinPool.yml","Akka.Routing.RoundRobinPool.#ctor(System.Int32)":"Akka.Routing.RoundRobinPool.yml","Akka.Routing.RoundRobinPool.#ctor(System.Int32,Akka.Routing.Resizer)":"Akka.Routing.RoundRobinPool.yml","Akka.Routing.RoundRobinPool.#ctor(System.Int32,Akka.Routing.Resizer,Akka.Actor.SupervisorStrategy,System.String,System.Boolean)":"Akka.Routing.RoundRobinPool.yml","Akka.Routing.RoundRobinPool.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.RoundRobinPool.yml","Akka.Routing.RoundRobinPool.GetNrOfInstances(Akka.Actor.ActorSystem)":"Akka.Routing.RoundRobinPool.yml","Akka.Routing.RoundRobinPool.WithSupervisorStrategy(Akka.Actor.SupervisorStrategy)":"Akka.Routing.RoundRobinPool.yml","Akka.Routing.RoundRobinPool.WithResizer(Akka.Routing.Resizer)":"Akka.Routing.RoundRobinPool.yml","Akka.Routing.RoundRobinPool.WithDispatcher(System.String)":"Akka.Routing.RoundRobinPool.yml","Akka.Routing.RoundRobinPool.WithFallback(Akka.Routing.RouterConfig)":"Akka.Routing.RoundRobinPool.yml","Akka.Routing.RoundRobinPool.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.RoundRobinPool.yml","Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate":"Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.yml","Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.yml","Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.NrOfInstances":"Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.yml","Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.UsePoolDispatcher":"Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.yml","Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.Resizer":"Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.yml","Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.SupervisorStrategy":"Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.yml","Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.RouterDispatcher":"Akka.Routing.RoundRobinPool.RoundRobinPoolSurrogate.yml","Akka.Routing.RoundRobinGroup":"Akka.Routing.RoundRobinGroup.yml","Akka.Routing.RoundRobinGroup.#ctor(Akka.Configuration.Config)":"Akka.Routing.RoundRobinGroup.yml","Akka.Routing.RoundRobinGroup.#ctor(System.String[])":"Akka.Routing.RoundRobinGroup.yml","Akka.Routing.RoundRobinGroup.#ctor(System.Collections.Generic.IEnumerable{System.String})":"Akka.Routing.RoundRobinGroup.yml","Akka.Routing.RoundRobinGroup.#ctor(System.Collections.Generic.IEnumerable{Akka.Actor.IActorRef})":"Akka.Routing.RoundRobinGroup.yml","Akka.Routing.RoundRobinGroup.#ctor(System.Collections.Generic.IEnumerable{System.String},System.String)":"Akka.Routing.RoundRobinGroup.yml","Akka.Routing.RoundRobinGroup.GetPaths(Akka.Actor.ActorSystem)":"Akka.Routing.RoundRobinGroup.yml","Akka.Routing.RoundRobinGroup.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.RoundRobinGroup.yml","Akka.Routing.RoundRobinGroup.WithDispatcher(System.String)":"Akka.Routing.RoundRobinGroup.yml","Akka.Routing.RoundRobinGroup.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.RoundRobinGroup.yml","Akka.Routing.RoundRobinGroup.RoundRobinGroupSurrogate":"Akka.Routing.RoundRobinGroup.RoundRobinGroupSurrogate.yml","Akka.Routing.RoundRobinGroup.RoundRobinGroupSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.RoundRobinGroup.RoundRobinGroupSurrogate.yml","Akka.Routing.RoundRobinGroup.RoundRobinGroupSurrogate.Paths":"Akka.Routing.RoundRobinGroup.RoundRobinGroupSurrogate.yml","Akka.Routing.RoundRobinGroup.RoundRobinGroupSurrogate.RouterDispatcher":"Akka.Routing.RoundRobinGroup.RoundRobinGroupSurrogate.yml","Akka.Routing.Routee":"Akka.Routing.Routee.yml","Akka.Routing.Routee.NoRoutee":"Akka.Routing.Routee.yml","Akka.Routing.Routee.Send(System.Object,Akka.Actor.IActorRef)":"Akka.Routing.Routee.yml","Akka.Routing.Routee.Ask(System.Object,System.Nullable{System.TimeSpan})":"Akka.Routing.Routee.yml","Akka.Routing.Routee.FromActorRef(Akka.Actor.IActorRef)":"Akka.Routing.Routee.yml","Akka.Routing.ActorRefRoutee":"Akka.Routing.ActorRefRoutee.yml","Akka.Routing.ActorRefRoutee.Actor":"Akka.Routing.ActorRefRoutee.yml","Akka.Routing.ActorRefRoutee.#ctor(Akka.Actor.IActorRef)":"Akka.Routing.ActorRefRoutee.yml","Akka.Routing.ActorRefRoutee.Send(System.Object,Akka.Actor.IActorRef)":"Akka.Routing.ActorRefRoutee.yml","Akka.Routing.ActorRefRoutee.Ask(System.Object,System.Nullable{System.TimeSpan})":"Akka.Routing.ActorRefRoutee.yml","Akka.Routing.ActorRefRoutee.Equals(System.Object)":"Akka.Routing.ActorRefRoutee.yml","Akka.Routing.ActorRefRoutee.Equals(Akka.Routing.ActorRefRoutee)":"Akka.Routing.ActorRefRoutee.yml","Akka.Routing.ActorRefRoutee.GetHashCode":"Akka.Routing.ActorRefRoutee.yml","Akka.Routing.ActorSelectionRoutee":"Akka.Routing.ActorSelectionRoutee.yml","Akka.Routing.ActorSelectionRoutee.Selection":"Akka.Routing.ActorSelectionRoutee.yml","Akka.Routing.ActorSelectionRoutee.#ctor(Akka.Actor.ActorSelection)":"Akka.Routing.ActorSelectionRoutee.yml","Akka.Routing.ActorSelectionRoutee.Send(System.Object,Akka.Actor.IActorRef)":"Akka.Routing.ActorSelectionRoutee.yml","Akka.Routing.ActorSelectionRoutee.Ask(System.Object,System.Nullable{System.TimeSpan})":"Akka.Routing.ActorSelectionRoutee.yml","Akka.Routing.ActorSelectionRoutee.Equals(System.Object)":"Akka.Routing.ActorSelectionRoutee.yml","Akka.Routing.ActorSelectionRoutee.Equals(Akka.Routing.ActorSelectionRoutee)":"Akka.Routing.ActorSelectionRoutee.yml","Akka.Routing.ActorSelectionRoutee.GetHashCode":"Akka.Routing.ActorSelectionRoutee.yml","Akka.Routing.RouterEnvelope":"Akka.Routing.RouterEnvelope.yml","Akka.Routing.RouterEnvelope.#ctor(System.Object)":"Akka.Routing.RouterEnvelope.yml","Akka.Routing.RouterEnvelope.Message":"Akka.Routing.RouterEnvelope.yml","Akka.Routing.Broadcast":"Akka.Routing.Broadcast.yml","Akka.Routing.Broadcast.#ctor(System.Object)":"Akka.Routing.Broadcast.yml","Akka.Routing.SeveralRoutees":"Akka.Routing.SeveralRoutees.yml","Akka.Routing.SeveralRoutees.#ctor(Akka.Routing.Routee[])":"Akka.Routing.SeveralRoutees.yml","Akka.Routing.SeveralRoutees.Send(System.Object,Akka.Actor.IActorRef)":"Akka.Routing.SeveralRoutees.yml","Akka.Routing.RoutingLogic":"Akka.Routing.RoutingLogic.yml","Akka.Routing.RoutingLogic.Select(System.Object,Akka.Routing.Routee[])":"Akka.Routing.RoutingLogic.yml","Akka.Routing.Router":"Akka.Routing.Router.yml","Akka.Routing.Router.#ctor(Akka.Routing.RoutingLogic,Akka.Actor.IActorRef,Akka.Actor.IActorRef[])":"Akka.Routing.Router.yml","Akka.Routing.Router.#ctor(Akka.Routing.RoutingLogic,Akka.Routing.Routee[])":"Akka.Routing.Router.yml","Akka.Routing.Router.Routees":"Akka.Routing.Router.yml","Akka.Routing.Router.RoutingLogic":"Akka.Routing.Router.yml","Akka.Routing.Router.Route(System.Object,Akka.Actor.IActorRef)":"Akka.Routing.Router.yml","Akka.Routing.Router.Send(Akka.Routing.Routee,System.Object,Akka.Actor.IActorRef)":"Akka.Routing.Router.yml","Akka.Routing.Router.WithRoutees(Akka.Routing.Routee[])":"Akka.Routing.Router.yml","Akka.Routing.Router.AddRoutee(Akka.Routing.Routee)":"Akka.Routing.Router.yml","Akka.Routing.Router.AddRoutee(Akka.Actor.IActorRef)":"Akka.Routing.Router.yml","Akka.Routing.Router.AddRoutee(Akka.Actor.ActorSelection)":"Akka.Routing.Router.yml","Akka.Routing.Router.RemoveRoutee(Akka.Routing.Routee)":"Akka.Routing.Router.yml","Akka.Routing.Router.RemoveRoutee(Akka.Actor.IActorRef)":"Akka.Routing.Router.yml","Akka.Routing.Router.RemoveRoutee(Akka.Actor.ActorSelection)":"Akka.Routing.Router.yml","Akka.Routing.RouterConfig":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.#ctor":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.#ctor(System.String)":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.NoRouter":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.RouterDispatcher":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.RoutingLogicController(Akka.Routing.RoutingLogic)":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.IsManagementMessage(System.Object)":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.StopRouterWhenAllRouteesRemoved":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.WithFallback(Akka.Routing.RouterConfig)":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.VerifyConfig(Akka.Actor.ActorPath)":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.Equals(Akka.Routing.RouterConfig)":"Akka.Routing.RouterConfig.yml","Akka.Routing.RouterConfig.Equals(System.Object)":"Akka.Routing.RouterConfig.yml","Akka.Routing.Group":"Akka.Routing.Group.yml","Akka.Routing.Group.#ctor(System.Collections.Generic.IEnumerable{System.String},System.String)":"Akka.Routing.Group.yml","Akka.Routing.Group.Paths":"Akka.Routing.Group.yml","Akka.Routing.Group.GetPaths(Akka.Actor.ActorSystem)":"Akka.Routing.Group.yml","Akka.Routing.Group.Props":"Akka.Routing.Group.yml","Akka.Routing.Group.Equals(Akka.Routing.Group)":"Akka.Routing.Group.yml","Akka.Routing.Group.Equals(System.Object)":"Akka.Routing.Group.yml","Akka.Routing.Group.GetHashCode":"Akka.Routing.Group.yml","Akka.Routing.Pool":"Akka.Routing.Pool.yml","Akka.Routing.Pool.#ctor(System.Int32,Akka.Routing.Resizer,Akka.Actor.SupervisorStrategy,System.String,System.Boolean)":"Akka.Routing.Pool.yml","Akka.Routing.Pool.NrOfInstances":"Akka.Routing.Pool.yml","Akka.Routing.Pool.GetNrOfInstances(Akka.Actor.ActorSystem)":"Akka.Routing.Pool.yml","Akka.Routing.Pool.UsePoolDispatcher":"Akka.Routing.Pool.yml","Akka.Routing.Pool.Resizer":"Akka.Routing.Pool.yml","Akka.Routing.Pool.SupervisorStrategy":"Akka.Routing.Pool.yml","Akka.Routing.Pool.Props(Akka.Actor.Props)":"Akka.Routing.Pool.yml","Akka.Routing.Pool.StopRouterWhenAllRouteesRemoved":"Akka.Routing.Pool.yml","Akka.Routing.Pool.DefaultSupervisorStrategy":"Akka.Routing.Pool.yml","Akka.Routing.Pool.Equals(Akka.Routing.Pool)":"Akka.Routing.Pool.yml","Akka.Routing.Pool.Equals(System.Object)":"Akka.Routing.Pool.yml","Akka.Routing.Pool.GetHashCode":"Akka.Routing.Pool.yml","Akka.Routing.CustomRouterConfig":"Akka.Routing.CustomRouterConfig.yml","Akka.Routing.CustomRouterConfig.#ctor":"Akka.Routing.CustomRouterConfig.yml","Akka.Routing.CustomRouterConfig.#ctor(System.String)":"Akka.Routing.CustomRouterConfig.yml","Akka.Routing.FromConfig":"Akka.Routing.FromConfig.yml","Akka.Routing.FromConfig.#ctor":"Akka.Routing.FromConfig.yml","Akka.Routing.FromConfig.#ctor(Akka.Routing.Resizer,Akka.Actor.SupervisorStrategy,System.String)":"Akka.Routing.FromConfig.yml","Akka.Routing.FromConfig.Instance":"Akka.Routing.FromConfig.yml","Akka.Routing.FromConfig.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.FromConfig.yml","Akka.Routing.FromConfig.VerifyConfig(Akka.Actor.ActorPath)":"Akka.Routing.FromConfig.yml","Akka.Routing.FromConfig.WithSupervisorStrategy(Akka.Actor.SupervisorStrategy)":"Akka.Routing.FromConfig.yml","Akka.Routing.FromConfig.WithResizer(Akka.Routing.Resizer)":"Akka.Routing.FromConfig.yml","Akka.Routing.FromConfig.WithDispatcher(System.String)":"Akka.Routing.FromConfig.yml","Akka.Routing.FromConfig.GetNrOfInstances(Akka.Actor.ActorSystem)":"Akka.Routing.FromConfig.yml","Akka.Routing.FromConfig.Props":"Akka.Routing.FromConfig.yml","Akka.Routing.FromConfig.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.FromConfig.yml","Akka.Routing.FromConfig.FromConfigSurrogate":"Akka.Routing.FromConfig.FromConfigSurrogate.yml","Akka.Routing.FromConfig.FromConfigSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.FromConfig.FromConfigSurrogate.yml","Akka.Routing.NoRouter":"Akka.Routing.NoRouter.yml","Akka.Routing.NoRouter.#ctor":"Akka.Routing.NoRouter.yml","Akka.Routing.NoRouter.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.NoRouter.yml","Akka.Routing.NoRouter.RouterDispatcher":"Akka.Routing.NoRouter.yml","Akka.Routing.NoRouter.WithFallback(Akka.Routing.RouterConfig)":"Akka.Routing.NoRouter.yml","Akka.Routing.NoRouter.Props(Akka.Actor.Props)":"Akka.Routing.NoRouter.yml","Akka.Routing.NoRouter.Instance":"Akka.Routing.NoRouter.yml","Akka.Routing.NoRouter.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.NoRouter.yml","Akka.Routing.NoRouter.NoRouterSurrogate":"Akka.Routing.NoRouter.NoRouterSurrogate.yml","Akka.Routing.NoRouter.NoRouterSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.NoRouter.NoRouterSurrogate.yml","Akka.Routing.RouterMessage":"Akka.Routing.RouterMessage.yml","Akka.Routing.RouterMessage.GetRoutees":"Akka.Routing.RouterMessage.yml","Akka.Routing.RouterManagementMessage":"Akka.Routing.RouterManagementMessage.yml","Akka.Routing.GetRoutees":"Akka.Routing.GetRoutees.yml","Akka.Routing.Routees":"Akka.Routing.Routees.yml","Akka.Routing.Routees.#ctor(System.Collections.Generic.IEnumerable{Akka.Routing.Routee})":"Akka.Routing.Routees.yml","Akka.Routing.Routees.Members":"Akka.Routing.Routees.yml","Akka.Routing.RemoveRoutee":"Akka.Routing.RemoveRoutee.yml","Akka.Routing.RemoveRoutee.#ctor(Akka.Routing.Routee)":"Akka.Routing.RemoveRoutee.yml","Akka.Routing.RemoveRoutee.Routee":"Akka.Routing.RemoveRoutee.yml","Akka.Routing.AddRoutee":"Akka.Routing.AddRoutee.yml","Akka.Routing.AddRoutee.#ctor(Akka.Routing.Routee)":"Akka.Routing.AddRoutee.yml","Akka.Routing.AddRoutee.Routee":"Akka.Routing.AddRoutee.yml","Akka.Routing.AdjustPoolSize":"Akka.Routing.AdjustPoolSize.yml","Akka.Routing.AdjustPoolSize.#ctor(System.Int32)":"Akka.Routing.AdjustPoolSize.yml","Akka.Routing.AdjustPoolSize.Change":"Akka.Routing.AdjustPoolSize.yml","Akka.Routing.ScatterGatherFirstCompletedRoutingLogic":"Akka.Routing.ScatterGatherFirstCompletedRoutingLogic.yml","Akka.Routing.ScatterGatherFirstCompletedRoutingLogic.#ctor(System.TimeSpan)":"Akka.Routing.ScatterGatherFirstCompletedRoutingLogic.yml","Akka.Routing.ScatterGatherFirstCompletedRoutingLogic.Select(System.Object,Akka.Routing.Routee[])":"Akka.Routing.ScatterGatherFirstCompletedRoutingLogic.yml","Akka.Routing.ScatterGatherFirstCompletedPool":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.#ctor(Akka.Configuration.Config)":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.#ctor(System.Int32)":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.#ctor(System.Int32,System.TimeSpan)":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.#ctor(System.Int32,Akka.Routing.Resizer,System.TimeSpan,Akka.Actor.SupervisorStrategy,System.String,System.Boolean)":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.Within":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.GetNrOfInstances(Akka.Actor.ActorSystem)":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.WithSupervisorStrategy(Akka.Actor.SupervisorStrategy)":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.WithResizer(Akka.Routing.Resizer)":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.WithDispatcher(System.String)":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.WithFallback(Akka.Routing.RouterConfig)":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.ScatterGatherFirstCompletedPool.yml","Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate":"Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.yml","Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.yml","Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.Within":"Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.yml","Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.NrOfInstances":"Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.yml","Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.UsePoolDispatcher":"Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.yml","Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.Resizer":"Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.yml","Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.SupervisorStrategy":"Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.yml","Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.RouterDispatcher":"Akka.Routing.ScatterGatherFirstCompletedPool.ScatterGatherFirstCompletedPoolSurrogate.yml","Akka.Routing.ScatterGatherFirstCompletedGroup":"Akka.Routing.ScatterGatherFirstCompletedGroup.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.#ctor(Akka.Configuration.Config)":"Akka.Routing.ScatterGatherFirstCompletedGroup.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.#ctor(System.TimeSpan,System.String[])":"Akka.Routing.ScatterGatherFirstCompletedGroup.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.#ctor(System.Collections.Generic.IEnumerable{System.String},System.TimeSpan)":"Akka.Routing.ScatterGatherFirstCompletedGroup.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.#ctor(System.Collections.Generic.IEnumerable{Akka.Actor.IActorRef},System.TimeSpan)":"Akka.Routing.ScatterGatherFirstCompletedGroup.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.#ctor(System.Collections.Generic.IEnumerable{System.String},System.TimeSpan,System.String)":"Akka.Routing.ScatterGatherFirstCompletedGroup.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.Within":"Akka.Routing.ScatterGatherFirstCompletedGroup.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.CreateRouter(Akka.Actor.ActorSystem)":"Akka.Routing.ScatterGatherFirstCompletedGroup.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.GetPaths(Akka.Actor.ActorSystem)":"Akka.Routing.ScatterGatherFirstCompletedGroup.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.WithDispatcher(System.String)":"Akka.Routing.ScatterGatherFirstCompletedGroup.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.ScatterGatherFirstCompletedGroup.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.ScatterGatherFirstCompletedGroupSurrogate":"Akka.Routing.ScatterGatherFirstCompletedGroup.ScatterGatherFirstCompletedGroupSurrogate.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.ScatterGatherFirstCompletedGroupSurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Routing.ScatterGatherFirstCompletedGroup.ScatterGatherFirstCompletedGroupSurrogate.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.ScatterGatherFirstCompletedGroupSurrogate.Within":"Akka.Routing.ScatterGatherFirstCompletedGroup.ScatterGatherFirstCompletedGroupSurrogate.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.ScatterGatherFirstCompletedGroupSurrogate.Paths":"Akka.Routing.ScatterGatherFirstCompletedGroup.ScatterGatherFirstCompletedGroupSurrogate.yml","Akka.Routing.ScatterGatherFirstCompletedGroup.ScatterGatherFirstCompletedGroupSurrogate.RouterDispatcher":"Akka.Routing.ScatterGatherFirstCompletedGroup.ScatterGatherFirstCompletedGroupSurrogate.yml","Akka.Serialization":"Akka.Serialization.yml","Akka.Serialization.JavaSerializer":"Akka.Serialization.JavaSerializer.yml","Akka.Serialization.JavaSerializer.#ctor(Akka.Actor.ExtendedActorSystem)":"Akka.Serialization.JavaSerializer.yml","Akka.Serialization.JavaSerializer.Identifier":"Akka.Serialization.JavaSerializer.yml","Akka.Serialization.JavaSerializer.IncludeManifest":"Akka.Serialization.JavaSerializer.yml","Akka.Serialization.JavaSerializer.ToBinary(System.Object)":"Akka.Serialization.JavaSerializer.yml","Akka.Serialization.JavaSerializer.FromBinary(System.Byte[],System.Type)":"Akka.Serialization.JavaSerializer.yml","Akka.Serialization.ByteArraySerializer":"Akka.Serialization.ByteArraySerializer.yml","Akka.Serialization.ByteArraySerializer.#ctor(Akka.Actor.ExtendedActorSystem)":"Akka.Serialization.ByteArraySerializer.yml","Akka.Serialization.ByteArraySerializer.Identifier":"Akka.Serialization.ByteArraySerializer.yml","Akka.Serialization.ByteArraySerializer.IncludeManifest":"Akka.Serialization.ByteArraySerializer.yml","Akka.Serialization.ByteArraySerializer.ToBinary(System.Object)":"Akka.Serialization.ByteArraySerializer.yml","Akka.Serialization.ByteArraySerializer.FromBinary(System.Byte[],System.Type)":"Akka.Serialization.ByteArraySerializer.yml","Akka.Serialization.NewtonSoftJsonSerializer":"Akka.Serialization.NewtonSoftJsonSerializer.yml","Akka.Serialization.NewtonSoftJsonSerializer.Settings":"Akka.Serialization.NewtonSoftJsonSerializer.yml","Akka.Serialization.NewtonSoftJsonSerializer.Serializer":"Akka.Serialization.NewtonSoftJsonSerializer.yml","Akka.Serialization.NewtonSoftJsonSerializer.#ctor(Akka.Actor.ExtendedActorSystem)":"Akka.Serialization.NewtonSoftJsonSerializer.yml","Akka.Serialization.NewtonSoftJsonSerializer.Identifier":"Akka.Serialization.NewtonSoftJsonSerializer.yml","Akka.Serialization.NewtonSoftJsonSerializer.IncludeManifest":"Akka.Serialization.NewtonSoftJsonSerializer.yml","Akka.Serialization.NewtonSoftJsonSerializer.ToBinary(System.Object)":"Akka.Serialization.NewtonSoftJsonSerializer.yml","Akka.Serialization.NewtonSoftJsonSerializer.FromBinary(System.Byte[],System.Type)":"Akka.Serialization.NewtonSoftJsonSerializer.yml","Akka.Serialization.NewtonSoftJsonSerializer.AkkaContractResolver":"Akka.Serialization.NewtonSoftJsonSerializer.AkkaContractResolver.yml","Akka.Serialization.NewtonSoftJsonSerializer.AkkaContractResolver.CreateProperty(System.Reflection.MemberInfo,Newtonsoft.Json.MemberSerialization)":"Akka.Serialization.NewtonSoftJsonSerializer.AkkaContractResolver.yml","Akka.Serialization.NewtonSoftJsonSerializer.SurrogateConverter":"Akka.Serialization.NewtonSoftJsonSerializer.SurrogateConverter.yml","Akka.Serialization.NewtonSoftJsonSerializer.SurrogateConverter.#ctor(Akka.Serialization.NewtonSoftJsonSerializer)":"Akka.Serialization.NewtonSoftJsonSerializer.SurrogateConverter.yml","Akka.Serialization.NewtonSoftJsonSerializer.SurrogateConverter.CanConvert(System.Type)":"Akka.Serialization.NewtonSoftJsonSerializer.SurrogateConverter.yml","Akka.Serialization.NewtonSoftJsonSerializer.SurrogateConverter.ReadJson(Newtonsoft.Json.JsonReader,System.Type,System.Object,Newtonsoft.Json.JsonSerializer)":"Akka.Serialization.NewtonSoftJsonSerializer.SurrogateConverter.yml","Akka.Serialization.NewtonSoftJsonSerializer.SurrogateConverter.WriteJson(Newtonsoft.Json.JsonWriter,System.Object,Newtonsoft.Json.JsonSerializer)":"Akka.Serialization.NewtonSoftJsonSerializer.SurrogateConverter.yml","Akka.Serialization.NullSerializer":"Akka.Serialization.NullSerializer.yml","Akka.Serialization.NullSerializer.#ctor(Akka.Actor.ExtendedActorSystem)":"Akka.Serialization.NullSerializer.yml","Akka.Serialization.NullSerializer.Identifier":"Akka.Serialization.NullSerializer.yml","Akka.Serialization.NullSerializer.IncludeManifest":"Akka.Serialization.NullSerializer.yml","Akka.Serialization.NullSerializer.ToBinary(System.Object)":"Akka.Serialization.NullSerializer.yml","Akka.Serialization.NullSerializer.FromBinary(System.Byte[],System.Type)":"Akka.Serialization.NullSerializer.yml","Akka.Serialization.Information":"Akka.Serialization.Information.yml","Akka.Serialization.Information.Address":"Akka.Serialization.Information.yml","Akka.Serialization.Information.System":"Akka.Serialization.Information.yml","Akka.Serialization.Serialization":"Akka.Serialization.Serialization.yml","Akka.Serialization.Serialization.SerializeWithTransport``1(Akka.Actor.ActorSystem,Akka.Actor.Address,System.Func{``0})":"Akka.Serialization.Serialization.yml","Akka.Serialization.Serialization.#ctor(Akka.Actor.ExtendedActorSystem)":"Akka.Serialization.Serialization.yml","Akka.Serialization.Serialization.System":"Akka.Serialization.Serialization.yml","Akka.Serialization.Serialization.AddSerializer(Akka.Serialization.Serializer)":"Akka.Serialization.Serialization.yml","Akka.Serialization.Serialization.AddSerializationMap(System.Type,Akka.Serialization.Serializer)":"Akka.Serialization.Serialization.yml","Akka.Serialization.Serialization.Deserialize(System.Byte[],System.Int32,System.Type)":"Akka.Serialization.Serialization.yml","Akka.Serialization.Serialization.Deserialize(System.Byte[],System.Int32,System.String)":"Akka.Serialization.Serialization.yml","Akka.Serialization.Serialization.FindSerializerFor(System.Object)":"Akka.Serialization.Serialization.yml","Akka.Serialization.Serialization.FindSerializerForType(System.Type)":"Akka.Serialization.Serialization.yml","Akka.Serialization.Serialization.SerializedActorPath(Akka.Actor.IActorRef)":"Akka.Serialization.Serialization.yml","Akka.Serialization.Serialization.GetSerializerById(System.Int32)":"Akka.Serialization.Serialization.yml","Akka.Serialization.Serializer":"Akka.Serialization.Serializer.yml","Akka.Serialization.Serializer.system":"Akka.Serialization.Serializer.yml","Akka.Serialization.Serializer.#ctor(Akka.Actor.ExtendedActorSystem)":"Akka.Serialization.Serializer.yml","Akka.Serialization.Serializer.Identifier":"Akka.Serialization.Serializer.yml","Akka.Serialization.Serializer.IncludeManifest":"Akka.Serialization.Serializer.yml","Akka.Serialization.Serializer.ToBinary(System.Object)":"Akka.Serialization.Serializer.yml","Akka.Serialization.Serializer.ToBinaryWithAddress(Akka.Actor.Address,System.Object)":"Akka.Serialization.Serializer.yml","Akka.Serialization.Serializer.FromBinary(System.Byte[],System.Type)":"Akka.Serialization.Serializer.yml","Akka.Serialization.Serializer.TypeQualifiedNameForManifest(System.Type)":"Akka.Serialization.Serializer.yml","Akka.Serialization.SerializerWithStringManifest":"Akka.Serialization.SerializerWithStringManifest.yml","Akka.Serialization.SerializerWithStringManifest.#ctor(Akka.Actor.ExtendedActorSystem)":"Akka.Serialization.SerializerWithStringManifest.yml","Akka.Serialization.SerializerWithStringManifest.IncludeManifest":"Akka.Serialization.SerializerWithStringManifest.yml","Akka.Serialization.SerializerWithStringManifest.FromBinary(System.Byte[],System.Type)":"Akka.Serialization.SerializerWithStringManifest.yml","Akka.Serialization.SerializerWithStringManifest.FromBinary(System.Byte[],System.String)":"Akka.Serialization.SerializerWithStringManifest.yml","Akka.Serialization.SerializerWithStringManifest.Manifest(System.Object)":"Akka.Serialization.SerializerWithStringManifest.yml","Akka.Serialization.SerializerIdentifierHelper":"Akka.Serialization.SerializerIdentifierHelper.yml","Akka.Serialization.SerializerIdentifierHelper.SerializationIdentifiers":"Akka.Serialization.SerializerIdentifierHelper.yml","Akka.Serialization.SerializerIdentifierHelper.GetSerializerIdentifierFromConfig(System.Type,Akka.Actor.ExtendedActorSystem)":"Akka.Serialization.SerializerIdentifierHelper.yml","Akka.Util":"Akka.Util.yml","Akka.Util.ByteIterator":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.Len":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.HasNext":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.Head":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.Next":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.Clear":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.Clone":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.Duplicate":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.Take(System.Int32)":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.Drop(System.Int32)":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.Slice(System.Int32,System.Int32)":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.TakeWhile(System.Func{System.Byte,System.Boolean})":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.DropWhile(System.Func{System.Byte,System.Boolean})":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.Span(System.Func{System.Byte,System.Boolean})":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.IndexWhere(System.Func{System.Byte,System.Boolean})":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.IndexOf(System.Byte)":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.ToByteString":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.ForEach(System.Action{System.Byte})":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.FoldLeft``1(``0,System.Func{``0,System.Byte,``0})":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.ToArray":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.GetByte":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.GetShort(Akka.IO.ByteOrder)":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.GetInt(Akka.IO.ByteOrder)":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.GetLong(Akka.IO.ByteOrder)":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.GetBytes(System.Byte[],System.Int32,System.Int32)":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.GetBytes(System.Int32)":"Akka.Util.ByteIterator.yml","Akka.Util.ByteIterator.CopyToBuffer(Akka.IO.ByteBuffer)":"Akka.Util.ByteIterator.yml","Akka.Util.ILinearSeq`1":"Akka.Util.ILinearSeq-1.yml","Akka.Util.ILinearSeq`1.IsEmpty":"Akka.Util.ILinearSeq-1.yml","Akka.Util.ILinearSeq`1.Head":"Akka.Util.ILinearSeq-1.yml","Akka.Util.ILinearSeq`1.Tail":"Akka.Util.ILinearSeq-1.yml","Akka.Util.ArrayLinearSeq`1":"Akka.Util.ArrayLinearSeq-1.yml","Akka.Util.ArrayLinearSeq`1.#ctor(`0[])":"Akka.Util.ArrayLinearSeq-1.yml","Akka.Util.ArrayLinearSeq`1.IsEmpty":"Akka.Util.ArrayLinearSeq-1.yml","Akka.Util.ArrayLinearSeq`1.Head":"Akka.Util.ArrayLinearSeq-1.yml","Akka.Util.ArrayLinearSeq`1.Tail":"Akka.Util.ArrayLinearSeq-1.yml","Akka.Util.ArrayLinearSeq`1.GetEnumerator":"Akka.Util.ArrayLinearSeq-1.yml","Akka.Util.ArrayLinearSeq`1.System#Collections#IEnumerable#GetEnumerator":"Akka.Util.ArrayLinearSeq-1.yml","Akka.Util.ArrayLinearSeq`1.op_Implicit(`0[])~Akka.Util.ArrayLinearSeq{`0}":"Akka.Util.ArrayLinearSeq-1.yml","Akka.Util.FastLazy`1":"Akka.Util.FastLazy-1.yml","Akka.Util.FastLazy`1.#ctor(System.Func{`0})":"Akka.Util.FastLazy-1.yml","Akka.Util.FastLazy`1.IsValueCreated":"Akka.Util.FastLazy-1.yml","Akka.Util.FastLazy`1.Value":"Akka.Util.FastLazy-1.yml","Akka.Util.Index`2":"Akka.Util.Index-2.yml","Akka.Util.Index`2.#ctor":"Akka.Util.Index-2.yml","Akka.Util.Index`2.Put(`0,`1)":"Akka.Util.Index-2.yml","Akka.Util.Index`2.FindValue(`0,System.Func{`1,System.Boolean})":"Akka.Util.Index-2.yml","Akka.Util.Index`2.Item(`0)":"Akka.Util.Index-2.yml","Akka.Util.Index`2.ForEach(System.Action{`0,`1})":"Akka.Util.Index-2.yml","Akka.Util.Index`2.Values":"Akka.Util.Index-2.yml","Akka.Util.Index`2.Keys":"Akka.Util.Index-2.yml","Akka.Util.Index`2.Remove(`0,`1)":"Akka.Util.Index-2.yml","Akka.Util.Index`2.RemoveValue(`1)":"Akka.Util.Index-2.yml","Akka.Util.Index`2.Remove(`0)":"Akka.Util.Index-2.yml","Akka.Util.Index`2.IsEmpty":"Akka.Util.Index-2.yml","Akka.Util.Index`2.Clear":"Akka.Util.Index-2.yml","Akka.Util.ISurrogate":"Akka.Util.ISurrogate.yml","Akka.Util.ISurrogate.FromSurrogate(Akka.Actor.ActorSystem)":"Akka.Util.ISurrogate.yml","Akka.Util.ISurrogated":"Akka.Util.ISurrogated.yml","Akka.Util.ISurrogated.ToSurrogate(Akka.Actor.ActorSystem)":"Akka.Util.ISurrogated.yml","Akka.Util.RuntimeDetector":"Akka.Util.RuntimeDetector.yml","Akka.Util.RuntimeDetector.IsMono":"Akka.Util.RuntimeDetector.yml","Akka.Util.Result`1":"Akka.Util.Result-1.yml","Akka.Util.Result`1.IsSuccess":"Akka.Util.Result-1.yml","Akka.Util.Result`1.Value":"Akka.Util.Result-1.yml","Akka.Util.Result`1.Exception":"Akka.Util.Result-1.yml","Akka.Util.Result`1.#ctor(`0)":"Akka.Util.Result-1.yml","Akka.Util.Result`1.#ctor(System.Exception)":"Akka.Util.Result-1.yml","Akka.Util.Result`1.Equals(Akka.Util.Result{`0})":"Akka.Util.Result-1.yml","Akka.Util.Result`1.Equals(System.Object)":"Akka.Util.Result-1.yml","Akka.Util.Result`1.GetHashCode":"Akka.Util.Result-1.yml","Akka.Util.Result`1.op_Equality(Akka.Util.Result{`0},Akka.Util.Result{`0})":"Akka.Util.Result-1.yml","Akka.Util.Result`1.op_Inequality(Akka.Util.Result{`0},Akka.Util.Result{`0})":"Akka.Util.Result-1.yml","Akka.Util.Result":"Akka.Util.Result.yml","Akka.Util.Result.Success``1(``0)":"Akka.Util.Result.yml","Akka.Util.Result.Failure``1(System.Exception)":"Akka.Util.Result.yml","Akka.Util.Result.FromTask``1(System.Threading.Tasks.Task{``0})":"Akka.Util.Result.yml","Akka.Util.Result.From``1(System.Func{``0})":"Akka.Util.Result.yml","Akka.Util.StandardOutWriter":"Akka.Util.StandardOutWriter.yml","Akka.Util.StandardOutWriter.Write(System.String,System.Nullable{System.ConsoleColor},System.Nullable{System.ConsoleColor})":"Akka.Util.StandardOutWriter.yml","Akka.Util.StandardOutWriter.WriteLine(System.String,System.Nullable{System.ConsoleColor},System.Nullable{System.ConsoleColor})":"Akka.Util.StandardOutWriter.yml","Akka.Util.Either`2":"Akka.Util.Either-2.yml","Akka.Util.Either`2.#ctor(`0,`1)":"Akka.Util.Either-2.yml","Akka.Util.Either`2.IsLeft":"Akka.Util.Either-2.yml","Akka.Util.Either`2.IsRight":"Akka.Util.Either-2.yml","Akka.Util.Either`2.Right":"Akka.Util.Either-2.yml","Akka.Util.Either`2.Left":"Akka.Util.Either-2.yml","Akka.Util.Either`2.Value":"Akka.Util.Either-2.yml","Akka.Util.Either`2.ToRight":"Akka.Util.Either-2.yml","Akka.Util.Either`2.ToLeft":"Akka.Util.Either-2.yml","Akka.Util.Either`2.op_Implicit(Akka.Util.Left{`0})~Akka.Util.Either{`0,`1}":"Akka.Util.Either-2.yml","Akka.Util.Either`2.op_Implicit(Akka.Util.Right{`1})~Akka.Util.Either{`0,`1}":"Akka.Util.Either-2.yml","Akka.Util.Either`2.Map``2(System.Func{`0,``0},System.Func{`1,``1})":"Akka.Util.Either-2.yml","Akka.Util.Either`2.MapLeft``1(System.Func{`0,``0})":"Akka.Util.Either-2.yml","Akka.Util.Either`2.MapRight``1(System.Func{`1,``0})":"Akka.Util.Either-2.yml","Akka.Util.Either`2.Fold``1(System.Func{`0,``0},System.Func{`1,``0})":"Akka.Util.Either-2.yml","Akka.Util.Either":"Akka.Util.Either.yml","Akka.Util.Either.Left``1(``0)":"Akka.Util.Either.yml","Akka.Util.Either.Right``1(``0)":"Akka.Util.Either.yml","Akka.Util.Right`2":"Akka.Util.Right-2.yml","Akka.Util.Right`2.#ctor(`1)":"Akka.Util.Right-2.yml","Akka.Util.Right`2.IsLeft":"Akka.Util.Right-2.yml","Akka.Util.Right`2.IsRight":"Akka.Util.Right-2.yml","Akka.Util.Right`2.Value":"Akka.Util.Right-2.yml","Akka.Util.Right`1":"Akka.Util.Right-1.yml","Akka.Util.Right`1.#ctor(`0)":"Akka.Util.Right-1.yml","Akka.Util.Right`1.Value":"Akka.Util.Right-1.yml","Akka.Util.Right`1.IsLeft":"Akka.Util.Right-1.yml","Akka.Util.Right`1.IsRight":"Akka.Util.Right-1.yml","Akka.Util.Left`2":"Akka.Util.Left-2.yml","Akka.Util.Left`2.#ctor(`0)":"Akka.Util.Left-2.yml","Akka.Util.Left`2.IsLeft":"Akka.Util.Left-2.yml","Akka.Util.Left`2.IsRight":"Akka.Util.Left-2.yml","Akka.Util.Left`2.Value":"Akka.Util.Left-2.yml","Akka.Util.Left`1":"Akka.Util.Left-1.yml","Akka.Util.Left`1.#ctor(`0)":"Akka.Util.Left-1.yml","Akka.Util.Left`1.Value":"Akka.Util.Left-1.yml","Akka.Util.Left`1.IsLeft":"Akka.Util.Left-1.yml","Akka.Util.Left`1.IsRight":"Akka.Util.Left-1.yml","Akka.Util.AtomicReference`1":"Akka.Util.AtomicReference-1.yml","Akka.Util.AtomicReference`1.#ctor(`0)":"Akka.Util.AtomicReference-1.yml","Akka.Util.AtomicReference`1.#ctor":"Akka.Util.AtomicReference-1.yml","Akka.Util.AtomicReference`1.atomicValue":"Akka.Util.AtomicReference-1.yml","Akka.Util.AtomicReference`1.Value":"Akka.Util.AtomicReference-1.yml","Akka.Util.AtomicReference`1.CompareAndSet(`0,`0)":"Akka.Util.AtomicReference-1.yml","Akka.Util.AtomicReference`1.GetAndSet(`0)":"Akka.Util.AtomicReference-1.yml","Akka.Util.AtomicReference`1.op_Implicit(Akka.Util.AtomicReference{`0})~`0":"Akka.Util.AtomicReference-1.yml","Akka.Util.AtomicReference`1.op_Implicit(`0)~Akka.Util.AtomicReference{`0}":"Akka.Util.AtomicReference-1.yml","Akka.Util.AtomicBoolean":"Akka.Util.AtomicBoolean.yml","Akka.Util.AtomicBoolean.#ctor(System.Boolean)":"Akka.Util.AtomicBoolean.yml","Akka.Util.AtomicBoolean.Value":"Akka.Util.AtomicBoolean.yml","Akka.Util.AtomicBoolean.CompareAndSet(System.Boolean,System.Boolean)":"Akka.Util.AtomicBoolean.yml","Akka.Util.AtomicBoolean.GetAndSet(System.Boolean)":"Akka.Util.AtomicBoolean.yml","Akka.Util.AtomicBoolean.op_Implicit(Akka.Util.AtomicBoolean)~System.Boolean":"Akka.Util.AtomicBoolean.yml","Akka.Util.AtomicBoolean.op_Implicit(System.Boolean)~Akka.Util.AtomicBoolean":"Akka.Util.AtomicBoolean.yml","Akka.Util.ConcurrentSet`1":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.#ctor":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.#ctor(System.Collections.Generic.IEnumerable{`0})":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.#ctor(System.Collections.Generic.IEqualityComparer{`0})":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.#ctor(System.Collections.Generic.IEnumerable{`0},System.Collections.Generic.IEqualityComparer{`0})":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.#ctor(System.Int32,System.Int32)":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.#ctor(System.Int32,System.Collections.Generic.IEnumerable{`0},System.Collections.Generic.IEqualityComparer{`0})":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.#ctor(System.Int32,System.Int32,System.Collections.Generic.IEqualityComparer{`0})":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.IsEmpty":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.Count":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.Clear":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.Contains(`0)":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.System#Collections#Generic#ICollection{T}#Add(`0)":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.System#Collections#Generic#ICollection{T}#CopyTo(`0[],System.Int32)":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.System#Collections#Generic#ICollection{T}#IsReadOnly":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.System#Collections#Generic#ICollection{T}#Remove(`0)":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.System#Collections#Generic#IEnumerable{T}#GetEnumerator":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.System#Collections#IEnumerable#GetEnumerator":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.TryAdd(`0)":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ConcurrentSet`1.TryRemove(`0)":"Akka.Util.ConcurrentSet-1.yml","Akka.Util.ListPriorityQueue":"Akka.Util.ListPriorityQueue.yml","Akka.Util.ListPriorityQueue.#ctor(System.Int32)":"Akka.Util.ListPriorityQueue.yml","Akka.Util.ListPriorityQueue.#ctor(System.Int32,System.Func{System.Object,System.Int32})":"Akka.Util.ListPriorityQueue.yml","Akka.Util.ListPriorityQueue.SetPriorityCalculator(System.Func{System.Object,System.Int32})":"Akka.Util.ListPriorityQueue.yml","Akka.Util.ListPriorityQueue.Enqueue(Akka.Actor.Envelope)":"Akka.Util.ListPriorityQueue.yml","Akka.Util.ListPriorityQueue.Dequeue":"Akka.Util.ListPriorityQueue.yml","Akka.Util.ListPriorityQueue.Peek":"Akka.Util.ListPriorityQueue.yml","Akka.Util.ListPriorityQueue.Count":"Akka.Util.ListPriorityQueue.yml","Akka.Util.ListPriorityQueue.ToString":"Akka.Util.ListPriorityQueue.yml","Akka.Util.ListPriorityQueue.IsConsistent":"Akka.Util.ListPriorityQueue.yml","Akka.Util.MonoConcurrentQueue`1":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.#ctor":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.#ctor(System.Collections.Generic.IEnumerable{`0})":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.IsEmpty":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.System#Collections#Concurrent#IProducerConsumerCollection{T}#TryAdd(`0)":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.System#Collections#IEnumerable#GetEnumerator":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.GetEnumerator":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.System#Collections#ICollection#CopyTo(System.Array,System.Int32)":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.CopyTo(`0[],System.Int32)":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.ToArray":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.System#Collections#ICollection#IsSynchronized":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.System#Collections#Concurrent#IProducerConsumerCollection{T}#TryTake(`0@)":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.System#Collections#ICollection#SyncRoot":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.Count":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.Enqueue(`0)":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.TryDequeue(`0@)":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MonoConcurrentQueue`1.TryPeek(`0@)":"Akka.Util.MonoConcurrentQueue-1.yml","Akka.Util.MurmurHash":"Akka.Util.MurmurHash.yml","Akka.Util.MurmurHash.StartMagicA":"Akka.Util.MurmurHash.yml","Akka.Util.MurmurHash.StartMagicB":"Akka.Util.MurmurHash.yml","Akka.Util.MurmurHash.StartHash(System.UInt32)":"Akka.Util.MurmurHash.yml","Akka.Util.MurmurHash.NextMagicA(System.UInt32)":"Akka.Util.MurmurHash.yml","Akka.Util.MurmurHash.NextMagicB(System.UInt32)":"Akka.Util.MurmurHash.yml","Akka.Util.MurmurHash.ExtendHash(System.UInt32,System.UInt32,System.UInt32,System.UInt32)":"Akka.Util.MurmurHash.yml","Akka.Util.MurmurHash.FinalizeHash(System.UInt32)":"Akka.Util.MurmurHash.yml","Akka.Util.MurmurHash.ByteHash(System.Byte[])":"Akka.Util.MurmurHash.yml","Akka.Util.MurmurHash.ArrayHash``1(``0[])":"Akka.Util.MurmurHash.yml","Akka.Util.MurmurHash.StringHash(System.String)":"Akka.Util.MurmurHash.yml","Akka.Util.MurmurHash.SymmetricHash``1(System.Collections.Generic.IEnumerable{``0},System.UInt32)":"Akka.Util.MurmurHash.yml","Akka.Util.BitArrayHelpers":"Akka.Util.BitArrayHelpers.yml","Akka.Util.BitArrayHelpers.ToBytes(System.Collections.BitArray)":"Akka.Util.BitArrayHelpers.yml","Akka.Util.IResolver":"Akka.Util.IResolver.yml","Akka.Util.IResolver.Resolve``1(System.Object[])":"Akka.Util.IResolver.yml","Akka.Util.Resolve":"Akka.Util.Resolve.yml","Akka.Util.Resolve.Produce":"Akka.Util.Resolve.yml","Akka.Util.Resolve.ActorType":"Akka.Util.Resolve.yml","Akka.Util.Resolve.Resolver":"Akka.Util.Resolve.yml","Akka.Util.Resolve.SetResolver(Akka.Util.IResolver)":"Akka.Util.Resolve.yml","Akka.Util.Resolve.Release(Akka.Actor.ActorBase)":"Akka.Util.Resolve.yml","Akka.Util.Resolve`1":"Akka.Util.Resolve-1.yml","Akka.Util.Resolve`1.#ctor(System.Object[])":"Akka.Util.Resolve-1.yml","Akka.Util.Resolve`1.Produce":"Akka.Util.Resolve-1.yml","Akka.Util.Resolve`1.ActorType":"Akka.Util.Resolve-1.yml","Akka.Util.Resolve`1.Arguments":"Akka.Util.Resolve-1.yml","Akka.Util.ThreadLocalRandom":"Akka.Util.ThreadLocalRandom.yml","Akka.Util.ThreadLocalRandom.Current":"Akka.Util.ThreadLocalRandom.yml","Akka.Util.TokenBucket":"Akka.Util.TokenBucket.yml","Akka.Util.TokenBucket.#ctor(System.Int64,System.Int64)":"Akka.Util.TokenBucket.yml","Akka.Util.TokenBucket.Init":"Akka.Util.TokenBucket.yml","Akka.Util.TokenBucket.CurrentTime":"Akka.Util.TokenBucket.yml","Akka.Util.TokenBucket.Offer(System.Int64)":"Akka.Util.TokenBucket.yml","Akka.Util.TickTimeTokenBucket":"Akka.Util.TickTimeTokenBucket.yml","Akka.Util.TickTimeTokenBucket.#ctor(System.Int64,System.Int64)":"Akka.Util.TickTimeTokenBucket.yml","Akka.Util.TickTimeTokenBucket.CurrentTime":"Akka.Util.TickTimeTokenBucket.yml","Akka.Util.Vector":"Akka.Util.Vector.yml","Akka.Util.Vector.Fill``1(System.Int32)":"Akka.Util.Vector.yml","Akka.Util.WildcardTree`1":"Akka.Util.WildcardTree-1.yml","Akka.Util.WildcardTree`1.#ctor":"Akka.Util.WildcardTree-1.yml","Akka.Util.WildcardTree`1.#ctor(`0,System.Collections.Generic.IDictionary{System.String,Akka.Util.WildcardTree{`0}})":"Akka.Util.WildcardTree-1.yml","Akka.Util.WildcardTree`1.Data":"Akka.Util.WildcardTree-1.yml","Akka.Util.WildcardTree`1.Children":"Akka.Util.WildcardTree-1.yml","Akka.Util.WildcardTree`1.Insert(System.Collections.Generic.IEnumerator{System.String},`0)":"Akka.Util.WildcardTree-1.yml","Akka.Util.WildcardTree`1.Find(System.Collections.Generic.IEnumerator{System.String})":"Akka.Util.WildcardTree-1.yml","Akka.Util.WildcardTree`1.Equals(System.Object)":"Akka.Util.WildcardTree-1.yml","Akka.Util.WildcardTree`1.GetHashCode":"Akka.Util.WildcardTree-1.yml","Akka.Util.WildcardTree`1.Empty":"Akka.Util.WildcardTree-1.yml","Akka.Util.Base64Encoding":"Akka.Util.Base64Encoding.yml","Akka.Util.Base64Encoding.Base64Chars":"Akka.Util.Base64Encoding.yml","Akka.Util.Base64Encoding.Base64Encode(System.Int64)":"Akka.Util.Base64Encoding.yml","Akka.Util.Base64Encoding.Base64Encode(System.String)":"Akka.Util.Base64Encoding.yml","Akka.Util.StringFormat":"Akka.Util.StringFormat.yml","Akka.Util.StringFormat.SafeJoin(System.String,System.Object[])":"Akka.Util.StringFormat.yml","Akka.Util.WildcardMatch":"Akka.Util.WildcardMatch.yml","Akka.Util.WildcardMatch.Like(System.String,System.String,System.Boolean)":"Akka.Util.WildcardMatch.yml","Akka.Util.Switch":"Akka.Util.Switch.yml","Akka.Util.Switch.#ctor(System.Boolean)":"Akka.Util.Switch.yml","Akka.Util.Switch.TranscendFrom(System.Boolean,System.Action)":"Akka.Util.Switch.yml","Akka.Util.Switch.SwitchOff(System.Action)":"Akka.Util.Switch.yml","Akka.Util.Switch.SwitchOn(System.Action)":"Akka.Util.Switch.yml","Akka.Util.Switch.SwitchOff":"Akka.Util.Switch.yml","Akka.Util.Switch.SwitchOn":"Akka.Util.Switch.yml","Akka.Util.Switch.IfOn(System.Action)":"Akka.Util.Switch.yml","Akka.Util.Switch.IfOff(System.Action)":"Akka.Util.Switch.yml","Akka.Util.Switch.WhileOn(System.Action)":"Akka.Util.Switch.yml","Akka.Util.Switch.WhileOff(System.Action)":"Akka.Util.Switch.yml","Akka.Util.Switch.IsOn":"Akka.Util.Switch.yml","Akka.Util.Switch.IsOff":"Akka.Util.Switch.yml","Akka.Util.Switch.Locked(System.Action)":"Akka.Util.Switch.yml","Akka.Util.TypeExtensions":"Akka.Util.TypeExtensions.yml","Akka.Util.TypeExtensions.Implements``1(System.Type)":"Akka.Util.TypeExtensions.yml","Akka.Util.TypeExtensions.Implements(System.Type,System.Type)":"Akka.Util.TypeExtensions.yml","Akka.Util.TypeExtensions.TypeQualifiedName(System.Type)":"Akka.Util.TypeExtensions.yml","Akka.Util.Internal":"Akka.Util.Internal.yml","Akka.Util.Internal.IAtomicState":"Akka.Util.Internal.IAtomicState.yml","Akka.Util.Internal.IAtomicState.AddListener(System.Action)":"Akka.Util.Internal.IAtomicState.yml","Akka.Util.Internal.IAtomicState.HasListeners":"Akka.Util.Internal.IAtomicState.yml","Akka.Util.Internal.IAtomicState.Invoke``1(System.Func{System.Threading.Tasks.Task{``0}})":"Akka.Util.Internal.IAtomicState.yml","Akka.Util.Internal.IAtomicState.Enter":"Akka.Util.Internal.IAtomicState.yml","Akka.Util.Internal.DictionaryExtensions":"Akka.Util.Internal.DictionaryExtensions.yml","Akka.Util.Internal.DictionaryExtensions.Put``2(System.Collections.Generic.IDictionary{``0,``1},``0,``1)":"Akka.Util.Internal.DictionaryExtensions.yml","Akka.Util.Internal.DictionaryExtensions.TryAdd``2(System.Collections.Generic.IDictionary{``0,``1},``0,``1)":"Akka.Util.Internal.DictionaryExtensions.yml","Akka.Util.Internal.InterlockedSpin":"Akka.Util.Internal.InterlockedSpin.yml","Akka.Util.Internal.InterlockedSpin.Swap``1(``0@,System.Func{``0,``0})":"Akka.Util.Internal.InterlockedSpin.yml","Akka.Util.Internal.InterlockedSpin.ConditionallySwap``2(``0@,System.Func{``0,System.Tuple{System.Boolean,``0,``1}})":"Akka.Util.Internal.InterlockedSpin.yml","Akka.Util.Internal.StringBuilderExtensions":"Akka.Util.Internal.StringBuilderExtensions.yml","Akka.Util.Internal.StringBuilderExtensions.AppendJoin``1(System.Text.StringBuilder,System.String,System.Collections.Generic.IEnumerable{``0})":"Akka.Util.Internal.StringBuilderExtensions.yml","Akka.Util.Internal.StringBuilderExtensions.AppendJoin``1(System.Text.StringBuilder,System.String,System.Collections.Generic.IEnumerable{``0},System.Action{System.Text.StringBuilder,``0,System.Int32})":"Akka.Util.Internal.StringBuilderExtensions.yml","Akka.Util.Internal.TaskExtensions":"Akka.Util.Internal.TaskExtensions.yml","Akka.Util.Internal.TaskExtensions.CastTask``2(System.Threading.Tasks.Task{``0})":"Akka.Util.Internal.TaskExtensions.yml","Akka.Util.Internal.Extensions":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.AsInstanceOf``1(System.Object)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.Drop``1(System.Collections.Generic.IEnumerable{``0},System.Int32)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.Head``1(System.Collections.Generic.IEnumerable{``0})":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.AlternateSelectMany``2(System.Collections.Generic.IEnumerable{``0},System.Func{``0,System.Collections.Generic.IEnumerable{``1}},System.Func{``0,System.Collections.Generic.IEnumerable{``1}})":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.SplitDottedPathHonouringQuotes(System.String)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.Join(System.Collections.Generic.IEnumerable{System.String},System.String)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.BetweenDoubleQuotes(System.String)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.AddOrSet``2(System.Collections.Generic.IDictionary{``0,``1},``0,``1)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.GetOrElse``2(System.Collections.Generic.IDictionary{``0,``1},``0,``1)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.GetOrElse``1(``0,``0)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.AddAndReturn``2(System.Collections.Generic.IDictionary{``0,``1},``0,``1)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.Max(System.TimeSpan,System.TimeSpan)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.Min(System.TimeSpan,System.TimeSpan)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.Concat``1(System.Collections.Generic.IEnumerable{``0},``0)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.ForEach``1(System.Collections.Generic.IEnumerable{``0},System.Action{``0})":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.Extensions.TakeRight``1(System.Collections.Generic.IEnumerable{``0},System.Int32)":"Akka.Util.Internal.Extensions.yml","Akka.Util.Internal.AtomicCounter":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.#ctor(System.Int32)":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.#ctor":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.Current":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.Next":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.Decrement":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.GetAndIncrement":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.IncrementAndGet":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.GetAndDecrement":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.DecrementAndGet":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.GetAndAdd(System.Int32)":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.AddAndGet(System.Int32)":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.Reset":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.GetAndSet(System.Int32)":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounter.CompareAndSet(System.Int32,System.Int32)":"Akka.Util.Internal.AtomicCounter.yml","Akka.Util.Internal.AtomicCounterLong":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.#ctor(System.Int64)":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.#ctor":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.Current":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.Next":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.GetAndIncrement":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.IncrementAndGet":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.DecrementAndGet":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.GetAndAdd(System.Int64)":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.AddAndGet(System.Int64)":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.Reset":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.GetAndSet(System.Int64)":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.CompareAndSet(System.Int64,System.Int64)":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.AtomicCounterLong.ToString":"Akka.Util.Internal.AtomicCounterLong.yml","Akka.Util.Internal.IAtomicCounter`1":"Akka.Util.Internal.IAtomicCounter-1.yml","Akka.Util.Internal.IAtomicCounter`1.Current":"Akka.Util.Internal.IAtomicCounter-1.yml","Akka.Util.Internal.IAtomicCounter`1.Next":"Akka.Util.Internal.IAtomicCounter-1.yml","Akka.Util.Internal.IAtomicCounter`1.GetAndIncrement":"Akka.Util.Internal.IAtomicCounter-1.yml","Akka.Util.Internal.IAtomicCounter`1.IncrementAndGet":"Akka.Util.Internal.IAtomicCounter-1.yml","Akka.Util.Internal.IAtomicCounter`1.GetAndAdd(`0)":"Akka.Util.Internal.IAtomicCounter-1.yml","Akka.Util.Internal.IAtomicCounter`1.AddAndGet(`0)":"Akka.Util.Internal.IAtomicCounter-1.yml","Akka.Util.Internal.IAtomicCounter`1.Reset":"Akka.Util.Internal.IAtomicCounter-1.yml","Akka.Util.Internal.Collections":"Akka.Util.Internal.Collections.yml","Akka.Util.Internal.Collections.EnumeratorExtensions":"Akka.Util.Internal.Collections.EnumeratorExtensions.yml","Akka.Util.Internal.Collections.EnumeratorExtensions.Iterator``1(System.Collections.Generic.IEnumerable{``0})":"Akka.Util.Internal.Collections.EnumeratorExtensions.yml","Akka.Util.Internal.Collections.Iterator`1":"Akka.Util.Internal.Collections.Iterator-1.yml","Akka.Util.Internal.Collections.Iterator`1.#ctor(System.Collections.Generic.IEnumerable{`0})":"Akka.Util.Internal.Collections.Iterator-1.yml","Akka.Util.Internal.Collections.Iterator`1.Next":"Akka.Util.Internal.Collections.Iterator-1.yml","Akka.Util.Internal.Collections.Iterator`1.IsEmpty":"Akka.Util.Internal.Collections.Iterator-1.yml","Akka.Util.Internal.Collections.Iterator`1.ToVector":"Akka.Util.Internal.Collections.Iterator-1.yml","Akka.Util.Internal.Collections.IBinaryTreeNode`2":"Akka.Util.Internal.Collections.IBinaryTreeNode-2.yml","Akka.Util.Internal.Collections.IBinaryTreeNode`2.Left":"Akka.Util.Internal.Collections.IBinaryTreeNode-2.yml","Akka.Util.Internal.Collections.IBinaryTreeNode`2.Right":"Akka.Util.Internal.Collections.IBinaryTreeNode-2.yml","Akka.Util.Internal.Collections.IKeyValuePair`2":"Akka.Util.Internal.Collections.IKeyValuePair-2.yml","Akka.Util.Internal.Collections.IKeyValuePair`2.Key":"Akka.Util.Internal.Collections.IKeyValuePair-2.yml","Akka.Util.Internal.Collections.IKeyValuePair`2.Value":"Akka.Util.Internal.Collections.IKeyValuePair-2.yml","Akka.Util.Reflection":"Akka.Util.Reflection.yml","Akka.Util.Reflection.TypeCache":"Akka.Util.Reflection.TypeCache.yml","Akka.Util.Reflection.TypeCache.GetType(System.String)":"Akka.Util.Reflection.TypeCache.yml","Akka.Util.Reflection.ExpressionExtensions":"Akka.Util.Reflection.ExpressionExtensions.yml","Akka.Util.Reflection.ExpressionExtensions.GetArguments(System.Linq.Expressions.NewExpression)":"Akka.Util.Reflection.ExpressionExtensions.yml","Akka.Tools.MatchHandler":"Akka.Tools.MatchHandler.yml","Akka.Tools.MatchHandler.IPartialHandlerArgumentsCapture`1":"Akka.Tools.MatchHandler.IPartialHandlerArgumentsCapture-1.yml","Akka.Tools.MatchHandler.IPartialHandlerArgumentsCapture`1.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.IPartialHandlerArgumentsCapture-1.yml","Akka.Tools.MatchHandler.IPartialHandlerArgumentsCapture`1.Handle(`0)":"Akka.Tools.MatchHandler.IPartialHandlerArgumentsCapture-1.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`1":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-1.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`1.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-1.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`1.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-1.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`2":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-2.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`2.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-2.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`2.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-2.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`3":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-3.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`3.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-3.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`3.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-3.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`4":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-4.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`4.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-4.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`4.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-4.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`5":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-5.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`5.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-5.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`5.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-5.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`6":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-6.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`6.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-6.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`6.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-6.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`7":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-7.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`7.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-7.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`7.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-7.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`8":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-8.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`8.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-8.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`8.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-8.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`9":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-9.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`9.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-9.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`9.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-9.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`10":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-10.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`10.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-10.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`10.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-10.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`11":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-11.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`11.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-11.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`11.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-11.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`12":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-12.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`12.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-12.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`12.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-12.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`13":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-13.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`13.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-13.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`13.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-13.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`14":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-14.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`14.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-14.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`14.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-14.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`15":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-15.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`15.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-15.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`15.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-15.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`16":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-16.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`16.Initialize(System.Delegate,System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-16.yml","Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture`16.Handle(`0)":"Akka.Tools.MatchHandler.PartialHandlerArgumentsCapture-16.yml","Akka.Tools.MatchHandler.Argument":"Akka.Tools.MatchHandler.Argument.yml","Akka.Tools.MatchHandler.Argument.#ctor(Akka.Tools.MatchHandler.PredicateAndHandler,System.Object,System.Boolean)":"Akka.Tools.MatchHandler.Argument.yml","Akka.Tools.MatchHandler.Argument.PredicateAndHandler":"Akka.Tools.MatchHandler.Argument.yml","Akka.Tools.MatchHandler.Argument.Value":"Akka.Tools.MatchHandler.Argument.yml","Akka.Tools.MatchHandler.Argument.ValueIsActionOrFunc":"Akka.Tools.MatchHandler.Argument.yml","Akka.Tools.MatchHandler.CachedMatchCompiler`1":"Akka.Tools.MatchHandler.CachedMatchCompiler-1.yml","Akka.Tools.MatchHandler.CachedMatchCompiler`1.Instance":"Akka.Tools.MatchHandler.CachedMatchCompiler-1.yml","Akka.Tools.MatchHandler.CachedMatchCompiler`1.#ctor(Akka.Tools.MatchHandler.IMatchExpressionBuilder,Akka.Tools.MatchHandler.IPartialActionBuilder,Akka.Tools.MatchHandler.ILambdaExpressionCompiler)":"Akka.Tools.MatchHandler.CachedMatchCompiler-1.yml","Akka.Tools.MatchHandler.CachedMatchCompiler`1.Compile(System.Collections.Generic.IReadOnlyList{Akka.Tools.MatchHandler.TypeHandler},System.Collections.Generic.IReadOnlyList{Akka.Tools.MatchHandler.Argument},Akka.Tools.MatchHandler.MatchBuilderSignature)":"Akka.Tools.MatchHandler.CachedMatchCompiler-1.yml","Akka.Tools.MatchHandler.CachedMatchCompiler`1.CompileToMethod(System.Collections.Generic.IReadOnlyList{Akka.Tools.MatchHandler.TypeHandler},System.Collections.Generic.IReadOnlyList{Akka.Tools.MatchHandler.Argument},Akka.Tools.MatchHandler.MatchBuilderSignature,System.Reflection.Emit.TypeBuilder,System.String,System.Reflection.MethodAttributes)":"Akka.Tools.MatchHandler.CachedMatchCompiler-1.yml","Akka.Tools.MatchHandler.CompiledMatchHandlerWithArguments":"Akka.Tools.MatchHandler.CompiledMatchHandlerWithArguments.yml","Akka.Tools.MatchHandler.CompiledMatchHandlerWithArguments.#ctor(System.Delegate,System.Object[])":"Akka.Tools.MatchHandler.CompiledMatchHandlerWithArguments.yml","Akka.Tools.MatchHandler.CompiledMatchHandlerWithArguments.CompiledDelegate":"Akka.Tools.MatchHandler.CompiledMatchHandlerWithArguments.yml","Akka.Tools.MatchHandler.CompiledMatchHandlerWithArguments.DelegateArguments":"Akka.Tools.MatchHandler.CompiledMatchHandlerWithArguments.yml","Akka.Tools.MatchHandler.ILambdaExpressionCompiler":"Akka.Tools.MatchHandler.ILambdaExpressionCompiler.yml","Akka.Tools.MatchHandler.ILambdaExpressionCompiler.Compile(System.Linq.Expressions.LambdaExpression)":"Akka.Tools.MatchHandler.ILambdaExpressionCompiler.yml","Akka.Tools.MatchHandler.ILambdaExpressionCompiler.CompileToMethod(System.Linq.Expressions.LambdaExpression,System.Reflection.Emit.MethodBuilder)":"Akka.Tools.MatchHandler.ILambdaExpressionCompiler.yml","Akka.Tools.MatchHandler.IMatchExpressionBuilder":"Akka.Tools.MatchHandler.IMatchExpressionBuilder.yml","Akka.Tools.MatchHandler.IMatchExpressionBuilder.BuildLambdaExpression(System.Collections.Generic.IReadOnlyList{Akka.Tools.MatchHandler.TypeHandler})":"Akka.Tools.MatchHandler.IMatchExpressionBuilder.yml","Akka.Tools.MatchHandler.IMatchExpressionBuilder.CreateArgumentValuesArray(System.Collections.Generic.IReadOnlyList{Akka.Tools.MatchHandler.Argument})":"Akka.Tools.MatchHandler.IMatchExpressionBuilder.yml","Akka.Tools.MatchHandler.IPartialActionBuilder":"Akka.Tools.MatchHandler.IPartialActionBuilder.yml","Akka.Tools.MatchHandler.IPartialActionBuilder.Build``1(Akka.Tools.MatchHandler.CompiledMatchHandlerWithArguments)":"Akka.Tools.MatchHandler.IPartialActionBuilder.yml","Akka.Tools.MatchHandler.MatchExpressionBuilderResult":"Akka.Tools.MatchHandler.MatchExpressionBuilderResult.yml","Akka.Tools.MatchHandler.MatchExpressionBuilderResult.#ctor(System.Linq.Expressions.LambdaExpression,System.Object[])":"Akka.Tools.MatchHandler.MatchExpressionBuilderResult.yml","Akka.Tools.MatchHandler.MatchExpressionBuilderResult.LambdaExpression":"Akka.Tools.MatchHandler.MatchExpressionBuilderResult.yml","Akka.Tools.MatchHandler.MatchExpressionBuilderResult.Arguments":"Akka.Tools.MatchHandler.MatchExpressionBuilderResult.yml","Akka.Tools.MatchHandler.MatchExpressionBuilder`1":"Akka.Tools.MatchHandler.MatchExpressionBuilder-1.yml","Akka.Tools.MatchHandler.MatchExpressionBuilder`1.BuildLambdaExpression(System.Collections.Generic.IReadOnlyList{Akka.Tools.MatchHandler.TypeHandler})":"Akka.Tools.MatchHandler.MatchExpressionBuilder-1.yml","Akka.Tools.MatchHandler.MatchExpressionBuilder`1.CreateArgumentValuesArray(System.Collections.Generic.IReadOnlyList{Akka.Tools.MatchHandler.Argument})":"Akka.Tools.MatchHandler.MatchExpressionBuilder-1.yml","Akka.Tools.MatchHandler.PartialActionBuilder":"Akka.Tools.MatchHandler.PartialActionBuilder.yml","Akka.Tools.MatchHandler.PartialActionBuilder.MaxNumberOfArguments":"Akka.Tools.MatchHandler.PartialActionBuilder.yml","Akka.Tools.MatchHandler.PartialActionBuilder.Build``1(Akka.Tools.MatchHandler.CompiledMatchHandlerWithArguments)":"Akka.Tools.MatchHandler.PartialActionBuilder.yml","Akka.Tools.MatchHandler.HandlerKind":"Akka.Tools.MatchHandler.HandlerKind.yml","Akka.Tools.MatchHandler.HandlerKind.Action":"Akka.Tools.MatchHandler.HandlerKind.yml","Akka.Tools.MatchHandler.HandlerKind.ActionWithPredicate":"Akka.Tools.MatchHandler.HandlerKind.yml","Akka.Tools.MatchHandler.HandlerKind.Func":"Akka.Tools.MatchHandler.HandlerKind.yml","Akka.Tools.MatchHandler.IMatchCompiler`1":"Akka.Tools.MatchHandler.IMatchCompiler-1.yml","Akka.Tools.MatchHandler.IMatchCompiler`1.Compile(System.Collections.Generic.IReadOnlyList{Akka.Tools.MatchHandler.TypeHandler},System.Collections.Generic.IReadOnlyList{Akka.Tools.MatchHandler.Argument},Akka.Tools.MatchHandler.MatchBuilderSignature)":"Akka.Tools.MatchHandler.IMatchCompiler-1.yml","Akka.Tools.MatchHandler.IMatchCompiler`1.CompileToMethod(System.Collections.Generic.IReadOnlyList{Akka.Tools.MatchHandler.TypeHandler},System.Collections.Generic.IReadOnlyList{Akka.Tools.MatchHandler.Argument},Akka.Tools.MatchHandler.MatchBuilderSignature,System.Reflection.Emit.TypeBuilder,System.String,System.Reflection.MethodAttributes)":"Akka.Tools.MatchHandler.IMatchCompiler-1.yml","Akka.Tools.MatchHandler.MatchBuilder`1":"Akka.Tools.MatchHandler.MatchBuilder-1.yml","Akka.Tools.MatchHandler.MatchBuilder`1.#ctor(Akka.Tools.MatchHandler.IMatchCompiler{`0})":"Akka.Tools.MatchHandler.MatchBuilder-1.yml","Akka.Tools.MatchHandler.MatchBuilder`1.Match``1(System.Action{``0},System.Predicate{``0})":"Akka.Tools.MatchHandler.MatchBuilder-1.yml","Akka.Tools.MatchHandler.MatchBuilder`1.Match(System.Type,System.Action{`0},System.Predicate{`0})":"Akka.Tools.MatchHandler.MatchBuilder-1.yml","Akka.Tools.MatchHandler.MatchBuilder`1.Match``1(System.Func{``0,System.Boolean})":"Akka.Tools.MatchHandler.MatchBuilder-1.yml","Akka.Tools.MatchHandler.MatchBuilder`1.Match(System.Type,System.Func{`0,System.Boolean})":"Akka.Tools.MatchHandler.MatchBuilder-1.yml","Akka.Tools.MatchHandler.MatchBuilder`1.MatchAny(System.Action{`0})":"Akka.Tools.MatchHandler.MatchBuilder-1.yml","Akka.Tools.MatchHandler.MatchBuilder`1.Build":"Akka.Tools.MatchHandler.MatchBuilder-1.yml","Akka.Tools.MatchHandler.MatchBuilder`1.BuildToMethod(System.Reflection.Emit.TypeBuilder,System.String,System.Reflection.MethodAttributes)":"Akka.Tools.MatchHandler.MatchBuilder-1.yml","Akka.Tools.MatchHandler.MatchBuilder":"Akka.Tools.MatchHandler.MatchBuilder.yml","Akka.Tools.MatchHandler.MatchBuilder.#ctor(Akka.Tools.MatchHandler.IMatchCompiler{System.Object})":"Akka.Tools.MatchHandler.MatchBuilder.yml","Akka.Tools.MatchHandler.MatchBuilderSignature":"Akka.Tools.MatchHandler.MatchBuilderSignature.yml","Akka.Tools.MatchHandler.MatchBuilderSignature.#ctor(System.Collections.Generic.IReadOnlyList{System.Object})":"Akka.Tools.MatchHandler.MatchBuilderSignature.yml","Akka.Tools.MatchHandler.MatchBuilderSignature.Equals(Akka.Tools.MatchHandler.MatchBuilderSignature)":"Akka.Tools.MatchHandler.MatchBuilderSignature.yml","Akka.Tools.MatchHandler.MatchBuilderSignature.Equals(System.Object)":"Akka.Tools.MatchHandler.MatchBuilderSignature.yml","Akka.Tools.MatchHandler.MatchBuilderSignature.GetHashCode":"Akka.Tools.MatchHandler.MatchBuilderSignature.yml","Akka.Tools.MatchHandler.MatchBuilderSignature.ToString":"Akka.Tools.MatchHandler.MatchBuilderSignature.yml","Akka.Tools.MatchHandler.PartialAction`1":"Akka.Tools.MatchHandler.PartialAction-1.yml","Akka.Tools.MatchHandler.PredicateAndHandler":"Akka.Tools.MatchHandler.PredicateAndHandler.yml","Akka.Tools.MatchHandler.PredicateAndHandler.HandlerKind":"Akka.Tools.MatchHandler.PredicateAndHandler.yml","Akka.Tools.MatchHandler.PredicateAndHandler.Arguments":"Akka.Tools.MatchHandler.PredicateAndHandler.yml","Akka.Tools.MatchHandler.PredicateAndHandler.HandlerFirstArgumentShouldBeBaseType":"Akka.Tools.MatchHandler.PredicateAndHandler.yml","Akka.Tools.MatchHandler.PredicateAndHandler.ActionOrFuncExpression":"Akka.Tools.MatchHandler.PredicateAndHandler.yml","Akka.Tools.MatchHandler.PredicateAndHandler.PredicateExpression":"Akka.Tools.MatchHandler.PredicateAndHandler.yml","Akka.Tools.MatchHandler.PredicateAndHandler.CreateAction(System.Object,System.Object,System.Boolean)":"Akka.Tools.MatchHandler.PredicateAndHandler.yml","Akka.Tools.MatchHandler.PredicateAndHandler.CreateFunc(System.Object,System.Boolean)":"Akka.Tools.MatchHandler.PredicateAndHandler.yml","Akka.Tools.MatchHandler.LambdaExpressionCompiler":"Akka.Tools.MatchHandler.LambdaExpressionCompiler.yml","Akka.Tools.MatchHandler.LambdaExpressionCompiler.Compile(System.Linq.Expressions.LambdaExpression)":"Akka.Tools.MatchHandler.LambdaExpressionCompiler.yml","Akka.Tools.MatchHandler.LambdaExpressionCompiler.CompileToMethod(System.Linq.Expressions.LambdaExpression,System.Reflection.Emit.MethodBuilder)":"Akka.Tools.MatchHandler.LambdaExpressionCompiler.yml","Akka.Tools.MatchHandler.TypeHandler":"Akka.Tools.MatchHandler.TypeHandler.yml","Akka.Tools.MatchHandler.TypeHandler.#ctor(System.Type)":"Akka.Tools.MatchHandler.TypeHandler.yml","Akka.Tools.MatchHandler.TypeHandler.HandlesType":"Akka.Tools.MatchHandler.TypeHandler.yml","Akka.Tools.MatchHandler.TypeHandler.Handlers":"Akka.Tools.MatchHandler.TypeHandler.yml","Akka.Tools.MatchHandler.TypeHandler.GetArguments":"Akka.Tools.MatchHandler.TypeHandler.yml"} \ No newline at end of file diff --git a/docs/api/index.md b/docs/api/index.md index 78dc9c00575..bd19f09a59c 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -1,2 +1 @@ -# PLACEHOLDER -TODO: Add .NET projects to the *src* folder and run `docfx` to generate **REAL** *API Documentation*! +## Akka.NET API Documentation \ No newline at end of file diff --git a/docs/articles/actors/dependency-injection.md b/docs/articles/actors/dependency-injection.md index 3c4844e7897..7d3f707855c 100644 --- a/docs/articles/actors/dependency-injection.md +++ b/docs/articles/actors/dependency-injection.md @@ -48,7 +48,7 @@ protected override void PreStart() > [!INFO] > There is currently still an extension method available for the actor Context. `Context.DI().ActorOf<>`. However this has been officially **deprecated** and will be removed in future versions. -##Notes +## Notes > [!WARNING] > You might be tempted at times to use an `IndirectActorProducer` diff --git a/docs/articles/actors/finite-state-machine.md b/docs/articles/actors/finite-state-machine.md index 5115e0c2b80..0a605971e23 100644 --- a/docs/articles/actors/finite-state-machine.md +++ b/docs/articles/actors/finite-state-machine.md @@ -16,15 +16,15 @@ using Akka.Event; The contract of our `Buncher` actor is that it accepts or produces the following messages: -[!code-csharp[Main](../../examples/Actors/FiniteStateMachine/FiniteStateMachine.Messages.cs#L11-L43)] +[!code-csharp[Main](../../examples/DocsExamples/Actors/FiniteStateMachine/FiniteStateMachine.Messages.cs#L11-L43)] `SetTarget` is needed for starting it up, setting the destination for the Batches to be passed on; `Queue` will add to the internal queue while `Flush` will mark the end of a burst. -[!code-csharp[Main](../../examples/Actors/FiniteStateMachine/FiniteStateMachine.Messages.cs#L46-L78)] +[!code-csharp[Main](../../examples/DocsExamples/Actors/FiniteStateMachine/FiniteStateMachine.Messages.cs#L46-L78)] The actor can be in two states: no message queued (aka `Idle`) or some message queued (aka `Active`). It will stay in the active state as long as messages keep arriving and no flush is requested. The internal state data of the actor is made up of the target actor reference to send the batches to and the actual queue of messages. -[!code-csharp[Main](../../examples/Actors/FiniteStateMachine/ExampleFSMActor.cs?range=8-35,64-67)] +[!code-csharp[Main](../../examples/DocsExamples/Actors/FiniteStateMachine/ExampleFSMActor.cs?range=8-35,64-67)] The basic strategy is to declare the actor, inherit from `FSM` class and specifying the possible states and data values as type parameters. Within the body of the actor a DSL is used for declaring the state machine: @@ -34,19 +34,19 @@ The basic strategy is to declare the actor, inherit from `FSM` class and specify In this case, we start out in the `Idle` and `Uninitialized` state, where only the `SetTarget()` message is handled; stay prepares to end this event’s processing for not leaving the current state, while the using modifier makes the `FSM` replace the internal state (which is `Uninitialized` at this point) with a fresh `Todo()` object containing the target actor reference. The `Active` state has a state timeout declared, which means that if no message is received for 1 second, a `FSM.StateTimeout` message will be generated. This has the same effect as receiving the `Flush` command in this case, namely to transition back into the Idle state and resetting the internal queue to the empty vector. But how do messages get queued? Since this shall work identically in both states, we make use of the fact that any event which is not handled by the `When()` block is passed to the `WhenUnhandled()` block: -[!code-csharp[Main](../../examples/Actors/FiniteStateMachine/ExampleFSMActor.cs?range=37-48)] +[!code-csharp[Main](../../examples/DocsExamples/Actors/FiniteStateMachine/ExampleFSMActor.cs?range=37-48)] The first case handled here is adding `Queue()` requests to the internal queue and going to the `Active` state (this does the obvious thing of staying in the `Active` state if already there), but only if the `FSM` data are not `Uninitialized` when the `Queue()` event is received. Otherwise—and in all other non-handled cases—the second case just logs a warning and does not change the internal state. The only missing piece is where the `Batches` are actually sent to the target, for which we use the `OnTransition` mechanism: you can declare multiple such blocks and all of them will be tried for matching behavior in case a state transition occurs (i.e. only when the state actually changes). -[!code-csharp[Main](../../examples/Actors/FiniteStateMachine/ExampleFSMActor.cs?range=50-63)] +[!code-csharp[Main](../../examples/DocsExamples/Actors/FiniteStateMachine/ExampleFSMActor.cs?range=50-63)] The transition callback is a function which takes as input a pair of states—the current and the next state. The `FSM` class includes a convenience extractor for these in form of an arrow operator, which conveniently reminds you of the direction of the state change which is being matched. During the state change, the old state data is available via `StateData` as shown, and the new state data would be available as `NextStateData`. To verify that this buncher actually works, it is quite easy to write a test using the `Testing Actor Systems`. -[!code-csharp[Main](../../examples/Actors/FiniteStateMachine/ExampleFSMActorTests.cs?range=9-33)] +[!code-csharp[Main](../../examples/DocsExamples/Actors/FiniteStateMachine/ExampleFSMActorTests.cs?range=9-33)] ## Reference @@ -86,7 +86,7 @@ If the `timeout` parameter is given, then all transitions into this state, inclu The `stateFunction` argument is a `delegate State StateFunction(Event fsmEvent)`. -[!code-csharp[Main](../../examples/Actors/FiniteStateMachine/ExampleFSMActor.cs?range=16-35)] +[!code-csharp[Main](../../examples/DocsExamples/Actors/FiniteStateMachine/ExampleFSMActor.cs?range=16-35)] ### Defining the Initial State Each `FSM` needs a starting point, which is declared using diff --git a/docs/articles/actors/mailboxes.md b/docs/articles/actors/mailboxes.md index b76f27185ac..3e4d826e712 100644 --- a/docs/articles/actors/mailboxes.md +++ b/docs/articles/actors/mailboxes.md @@ -58,7 +58,7 @@ my-custom-mailbox { The unbounded mailbox priority mailbox is blocking mailbox that allows message prioritization, so that you can choose the order the actor should process messages that are already in the mailbox. - In order to use this mailbox, you need to extend the `UnboundedPriorityMailbox` class and provide an ordering logic. The value returned by the `PriorityGenerator` method will be used to order the message in the mailbox. Lower values will be delivered first. Messages ordered by the same number will remain in delivery order. + In order to use this mailbox, you need to extend the `UnboundedPriorityMailbox` class and provide an ordering logic. The value returned by the `PriorityGenerator` method will be used to order the message in the mailbox. Lower values will be delivered first. Delivery order for messages of equal priority is undefined. ```cs public class IssueTrackerMailbox : UnboundedPriorityMailbox @@ -82,3 +82,6 @@ my-custom-mailbox { ``` Once the class is implemented, you should set it up using the [instructions above](#using-a-mailbox). +##### Special note +While we have updated the UnboundedPriorityMailbox to support Stashing. We don't recommend using it. +Once you stash messages, they are no longer part of the prioritization process that your PriorityMailbox uses. Once you unstash all messages, they are fed to the Actor, in the order of stashing. diff --git a/docs/articles/actors/receive-actor-api.md b/docs/articles/actors/receive-actor-api.md index 6ec1d58c57b..374b911ec04 100644 --- a/docs/articles/actors/receive-actor-api.md +++ b/docs/articles/actors/receive-actor-api.md @@ -151,7 +151,7 @@ This strategy is typically declared inside the actor in order to have access to * parent supervisor * supervised children * lifecycle monitoring - * hotswap behavior stack as described in [HotSwap](#become/unbecome) + * hotswap behavior stack as described in [HotSwap](#becomeunbecome) The remaining visible methods are user-overridable life-cycle hooks which are described in the following: diff --git a/docs/articles/actors/testing-actor-systems.md b/docs/articles/actors/testing-actor-systems.md index 25aea536058..33e6a68c1b9 100644 --- a/docs/articles/actors/testing-actor-systems.md +++ b/docs/articles/actors/testing-actor-systems.md @@ -3,132 +3,29 @@ uid: testing-actor-systems title: Testing Actor Systems --- + # Testing Actor Systems -As with any piece of software, automated tests are a very important part of the development cycle. The actor model presents a different view on how units of code are delimited and how they interact, which has an influence on how to perform tests. -Akka.Net comes with a dedicated module `Akka.TestKit` for supporting tests at different levels, which fall into two clearly distinct categories: -- Testing isolated pieces of code without involving the actor model, meaning without multiple threads; this implies completely deterministic behavior concerning the ordering of events and no concurrency concerns and will be called **Unit Testing** in the following. -- Testing (multiple) encapsulated actors including multi-threaded scheduling; this implies non-deterministic order of events but shielding from concurrency concerns by the actor model and will be called **Integration Testing** in the following. +As with any piece of software, automated tests are a very important part of the development cycle. The actor model presents a different view on how units of code are delimited and how they interact, which has an influence on how to perform tests. -There are of course variations on the granularity of tests in both categories, where unit testing reaches down to white-box tests and integration testing can encompass functional tests of complete actor networks. The important distinction lies in whether concurrency concerns are part of the test or not. The tools offered are described in detail in the following sections. +Akka.Net comes with a dedicated module `Akka.TestKit` for supporting tests at different levels. -## Synchronous Unit Testing with TestActorRef +## Asynchronous Testing: TestKit -Testing the business logic inside `Actor` classes can be divided into two parts: first, each atomic operation must work in isolation, then sequences of incoming events must be processed correctly, even in the presence of some possible variability in the ordering of events. The former is the primary use case for single-threaded unit testing, while the latter can only be verified in integration tests. +Testkit allows you to test your actors in a controlled but realistic environment. The definition of the environment depends of course very much on the problem at hand and the level at which you intend to test, ranging from simple checks to full system tests. -Normally, the `IActorRef` shields the underlying `Actor` instance from the outside, the only communications channel is the actor's mailbox. This restriction is an impediment to unit testing, which led to the inception of the `TestActorRef`. This special type of reference is designed specifically for test purposes and allows access to the actor in two ways: either by obtaining a reference to the underlying actor instance, or by invoking or querying the actor's behaviour (receive). Each one warrants its own section below. - -> [!NOTE] -> It is highly recommended to stick to traditional behavioural testing (using messaging to ask the `Actor` to reply with the state you want to run assertions against), instead of using `TestActorRef` whenever possible. - -### Obtaining a Reference to an Actor -Having access to the actual `Actor` object allows application of all traditional unit testing techniques on the contained methods. Obtaining a reference is done like this: -```csharp -public class MyActor : UntypedActor -{ - protected override void OnReceive(object message) - { - if (message.Equals("say42")) - { - Sender.Tell(42, Self); - } - else if (message is Exception) - { - throw (Exception)message; - } - } - - public bool TestMe - { - get { return true; } - } -} - -[Fact] -public void DemonstrateTestActorRef() -{ - var props = Props.Create(); - var myTestActor = new TestActorRef(Sys, props, null, "testA"); - MyActor myActor = myTestActor.UnderlyingActor; - Assert.True(myActor.TestMe); -} -``` -Since `TestActorRef` is generic in the actor type it returns the underlying actor with its proper static type. From this point on you may bring any unit testing tool to bear on your actor as usual. - -### Testing the Actor's Behavior -When the dispatcher invokes the processing behavior of an actor on a message, it actually calls apply on the current behavior registered for the actor. This starts out with the return value of the declared receive method, but it may also be changed using become and unbecome in response to external messages. All of this contributes to the overall actor behavior and it does not lend itself to easy testing on the `Actor` itself. Therefore the TestActorRef offers a different mode of operation to complement the `Actor` testing: it supports all operations also valid on normal `IActorRef`. Messages sent to the actor are processed synchronously on the current thread and answers may be sent back as usual. This trick is made possible by the `CallingThreadDispatcher` described below; this dispatcher is set implicitly for any actor instantiated into a `TestActorRef`. -```csharp -var props = Props.Create(); -var myTestActor = new TestActorRef(Sys, props, null, "testB"); -Task future = myTestActor.Ask("say42", TimeSpan.FromMilliseconds(3000)); -Assert.True(future.IsCompleted); -Assert.Equal(42, await future); -``` -As the `TestActorRef` is a subclass of `LocalActorRef` with a few special extras, also aspects like supervision and restarting work properly, but beware that execution is only strictly synchronous as long as all actors involved use the `CallingThreadDispatcher`. As soon as you add elements which include more sophisticated scheduling you leave the realm of unit testing as you then need to think about asynchronicity again (in most cases the problem will be to wait until the desired effect had a chance to happen). - -One more special aspect which is overridden for single-threaded tests is the `ReceiveTimeout`, as including that would entail asynchronous queuing of `ReceiveTimeout` messages, violating the synchronous contract. - -### The Way In-Between: Expecting Exceptions -If you want to test the actor behavior, including hotswapping, but without involving a dispatcher and without having the `TestActorRef` swallow any thrown exceptions, then there is another mode available for you: just use the receive method on `TestActorRef`, which will be forwarded to the underlying actor: -```csharp -var props = Props.Create(); -var myTestActor = new TestActorRef(Sys, props, null, "testB"); -try -{ - myTestActor.Receive(new Exception("expected")); -} -catch (Exception e) -{ - Assert.Equal("expected", e.Message); -} -``` - -### Use Cases -You may of course mix and match both modi operandi of `TestActorRef` as suits your test needs: - -- one common use case is setting up the actor into a specific internal state before sending the test message -- another is to verify correct internal state transitions after having sent the test message - -## Asynchronous Integration Testing with TestKit -When you are reasonably sure that your actor's business logic is correct, the next step is verifying that it works correctly within its intended environment (if the individual actors are simple enough, possibly because they use the `FSM` module, this might also be the first step). The definition of the environment depends of course very much on the problem at hand and the level at which you intend to test, ranging for functional/integration tests to full system tests. The minimal setup consists of the test procedure, which provides the desired stimuli, the actor under test, and an actor receiving replies. Bigger systems replace the actor under test with a network of actors, apply stimuli at varying injection points and arrange results to be sent from different emission points, but the basic principle stays the same in that a single procedure drives the test. +The minimal setup consists of the test procedure, which provides the desired stimuli, the actor under test, and an actor receiving replies. Bigger systems replace the actor under test with a network of actors, apply stimuli at varying injection points and arrange results to be sent from different emission points, but the basic principle stays the same in that a single procedure drives the test. The `TestKit` class contains a collection of tools which makes this common task easy. -```csharp -public class MyActor : UntypedActor -{ - protected override void OnReceive(object message) - { - if (message.Equals("hello world")) - { - Sender.Tell(message, Self); - } - else - { - Unhandled(message); - } - } - - public bool TestMe - { - get { return true; } - } -} +[!code-csharp[IntroSample](../../examples/DocsExamples/Testkit/TestKitSampleTest.cs?range=9-64)] -[Fact] -public void EndBackMessagesUnchanged() -{ - var echo = Sys.ActorOf(Props.Create()); - echo.Tell("hello world"); - ExpectMsg("hello world"); -} -``` -The `TestKit` contains an actor named `MyActor` which is the entry point for messages to be examined with the various `ExpectMsg...` assertions detailed below. When mixing in the class `ImplicitSender` this test actor is implicitly used as sender reference when dispatching messages from the test procedure. The `MyActor` may also be passed to other actors as usual, usually subscribing it as notification listener. There is a whole set of examination methods, e.g. receiving all consecutive messages matching certain criteria, receiving a whole sequence of fixed messages or classes, receiving nothing for some time, etc. +The `TestKit` contains an actor named `TestActor` which is the entry point for messages to be examined with the various `ExpectMsg..` assertions detailed below. The `TestActor` may also be passed to other actors as usual, usually subscribing it as notification listener. There is a while set of examination methods, e.g. receiving all consecutive messages matching certain criteria, receiving a while sequence of fixed messages or classes, receiving nothing for some time, etc. -The `ActorSystem` passed in to the constructor of `TestKit` is accessible via the system member. Remember to shut down the actor system after the test is finished (also in case of failure) so that all actors—including the test actor—are stopped. +You can provide your own ActorSystem instance, or Config by overriding the TestKit constructor. The ActorSystem used by the TestKit is accessible via the `Sys` member. -### Built-In Assertions +## Built-In Assertions The above mentioned `ExpectMsg` is not the only method for formulating assertions concerning received messages. Here is the full list: @@ -153,18 +50,161 @@ Receive one message of the specified type from the test actor and assert that it - `object FishForMessage(Predicate isMessage, TimeSpan? max, string)` Keep receiving messages as long as the time is not used up and the partial function matches and returns `false`. Returns the message received for which it returned `true` or throws an exception, which will include the provided hint for easier debugging. -### Expecting Log Messages +In addition to message reception assertions there are also methods which help with messages flows: + +- `object ReceiveOne(TimeSpan? max = null)` +Receive one message from the internal queue of the TestActor. This method blocks the specified duration or until a message is received. If no message was received, null is returned. + +- `IReadOnlyList ReceiveWhile(TimeSpan? max, TimeSpan? idle, Func filter, int msgs = int.MaxValue)` Collect messages as long as + - They are matching the provided filter + - The given time interval is not used up + - The next message is received within the idle timeout + - The number of messages has not yet reached the maximum All collected messages are returned. The maximum duration defaults to the time remaining in the innermost enclosing `Within` block and the idle duration defaults to infinity (thereby disabling the idle timeout feature). The number of expected messages defaults to `Int.MaxValue`, which effectively disables this limit. + +- `void AwaitCondition(Func conditionIsFulfilled, TimeSpan? max, TimeSpan? interval, string message = null)` Poll the given condition every `interval` until it returns `true` or the `max` duration is used up. The interval defaults to 100ms and the maximum defaults to the time remaining in the innermost enclosing `within` block. + +- `void AwaitAssert(Action assertion, TimeSpan? duration = default(TimeSpan?), TimeSpan? interval = default(TimeSpan?))`Poll the given assert function every `interval` until it does not throw an exception or the `max` duration is used up. If the timeout expires the last exception is thrown. The interval defaults to 100ms and the maximum defautls to the time remaining in the innermost enclosing `within` block. The interval defaults to 100ms and the maximum defaults to the time remaining in the innermost enclosing `within` block. + +- `void IgnoreMessages(Func shouldIgnoreMessage)` The internal `testActor` contains a partial function for ignoring messages: it will only enqueue messages which do not match the function or for which the function returns `false`. This feature is useful e.g. when testing a logging system, where you want to ignore regular messages and are only interesting in your specific ones. + +## Expecting Log Messages +Since an integration test does not allow to the internal processing of the participating actors, verifying expected exceptions cannot be done directly. Instead, use the logging system for this purpose: replacing the normal event handler with the `TestEventListener` and using an `EventFilter` allows assertions on log messages, including those which are generated by exceptions: -### Timing Assertions +//TODO EVENTFILTER SAMPLE -### Resolving Conflicts with Implicit IActorRef +If a number of occurrences is specific --as demonstrated above-- then `intercept` will block until that number of matching messages have been received or the timeout configured in `akka.test.filter-leeway` is used up (time starts counting after the passed-in block of code returns). In case of a timeout the test fails. -### Using Multiple Probe Actors +>[NOTE] +>By default the TestKit already loads the TestEventListener as a logger. Be aware that if you want to specify your own config. Use the `DefaultConfig` property to apply overrides. -### Testing parent-child relationships +## Timing Assertions +Another important part of functional testing concerns timing: certain events must not happen immediately (like a timer), others need to happen before a deadline. Therefore, all examination methods accept an upper time limit within the positive or negative result must be obtained. Lower time limits need to be checked external to the examination, which is facilitated by a new construct for managing time constraints: +[!code-csharp[WithinSample](../../examples/DocsExamples/Testkit/WithinSampleTest.cs?range=18-22)] + +The block in `within` must complete after a `Duration` which is between `min` and `max`, where the former defaults to zero. The deadline calculated by adding the `max` parameter to the block's start time is implicitly available within the block to all examination methods, if you do not specify it, it is inherited from the innermost enclosing `within` block. + +It should be noted that if the last message-receiving assertion of the block is `ExpectNoMsg` or `ReceiveWhile`, the final check of the within is skipped in order to avoid false positives due to wake-up latencies. This means that while individual contained assertions still use the maximum time bound, the overall block may take arbitrarily longer in this case. + +```csharp +var worker = ActorOf(); +Within(200.Milliseconds()) { + worker.Tell("some work"); + ExpectMsg("Some Result"); + ExpectNoMsg(); //will block for the rest of the 200ms + Thead.Sleep(300); //will NOT make this block fail +} + +## Accounting for Slow Test System +The tight timeouts you use during testing on your lightning-fast notebook will invariably lead to spurious test failures on your heavily loaded build server. To account for this situation, all maximum durations are internally scaled by a factor taken from the **Configuration**, `akka.test.timefactor`, which defaults to 1. + +You can scale other durations with the same factor by using the `Dilated` method in `TestKit`. + +//TODO DILATED EXAMPLE + +## Using Multiple Probe Actors + +When the actors under test are supposed to send various messages to different destinations, it may be difficult distinguishing the message streams arriving at the `TestActor` when using the `TestKit` as shown until now. Another approach is to use it for creation of simple probe actors to be inserted in the message flows. The functionality is best explained using a small example: + +[!code-csharp[ProbeSample](../../examples/DocsExamples/Testkit/ProbeSampleTest.cs?range=14-40)] + +This simple test verifies an equally simple Forwarder actor by injecting a probe as the forwarder’s target. Another example would be two actors A and B which collaborate by A sending messages to B. In order to verify this message flow, a `TestProbe` could be inserted as target of A, using the forwarding capabilities or auto-pilot described below to include a real B in the test setup. + +If you have many test probes, you can name them to get meaningful actor names in test logs and assertions: + +[!code-csharp[MultipleProbeSample](../../examples/DocsExamples/Testkit/ProbeSampleTest.cs?range=46-50)] + +Probes may also be equipped with custom assertions to make your test code even more concise and clear: + +//TODO CUSTOM PROBE IMPL SAMPLE + +You have complete flexibility here in mixing and matching the `TestKit` facilities with your own checks and choosing an intuitive name for it. In real life your code will probably be a bit more complicated than the example given above; just use the power! + +>[WARNING] +>Any message send from a `TestProbe` to another actor which runs on the `CallingThreadDispatcher` runs the risk of dead-lock, if that other actor might also send to this probe. The implementation of `TestProbe.Watch` and `TestProbe.Unwatch` will also send a message to the watchee, which means that it is dangerous to try watching e.g. `TestActorRef` from a `TestProbe`. + +###Watching Other Actors from probes +A `TestProbe` can register itself for DeathWatch of any other actor: + +```csharp + var probe = CreateTestProbe(); + probe.Watch(target); + + target.Tell(PoisonPill.Instance); + + var msg = probe.ExpectMsg(); + Assert.Equal(msg.ActorRef, target); +``` -## CallingThreadDispatcher +###Replying to Messages Received by Probes +The probes stores the sender of the last dequeued message (i.e. after its `ExpectMsg*` reception), which may be retrieved using the `GetLastSender()` method. This information can also implicitly be used for having the probe reply to the last received message: + +[!code-csharp[ReplyingToProbeMessages](../../examples/DocsExamples/Testkit/ProbeSampleTest.cs?range=57-62)] + +###Forwarding Messages Received by Probes +The probe can also forward a received message (i.e. after its `ExpectMsg*` reception), retaining the original sender: + +[!code-csharp[ForwardingProbeMessages](../../examples/DocsExamples/Testkit/ProbeSampleTest.cs?range=68-73)] + +###Auto-Pilot +Receiving messages in a queue for later inspection is nice, but in order to keep a test running and verify traces later you can also install an `AutoPilot` in the participating test probes (actually in any `TestKit`) which is invoked before enqueueing to the inspection queue. This code can be used to forward messages, e.g. in a chain `A --> Probe --> B`, as long as a certain protocol is obeyed. + +[!code-csharp[ProbeAutopilot](../../examples/DocsExamples/Testkit/ProbeSampleTest.cs?range=79-91)] + +The `run` method must return the auto-pilot for the next message. There are multiple options here: +You can return the `AutoPilot.NoAutoPilot` to stop the autopilot, or `AutoPilot.KeepRunning` to keep using the current `AutoPilot`. Obviously you can also chain a new `AutoPilot` instance to switch behaviors. + +###Caution about Timing Assertions +The behavior of `Within` blocks when using test probes might be perceived as counter-intuitive: you need to remember that the nicely scoped deadline as described **above** is local to each probe. Hence, probes do not react to each other's deadlines or to the deadline set in an enclosing `TestKit` instance. + +##Testing parent-child relationships + +The parent of an actor is always the actor that created it. At times this leads to a coupling between the two that may not be straightforward to test. There are several approaches to improve testability of a child actor that needs to refer to its parent: + +1. When creating a child, pass an explicit reference to its parent +2. Create the child with a `TestProbe` as parent +3. Create a fabricated parent when testing + +Conversely, a parent's binding to its child can be lessened as follows: + +1. When creating a parent, tell the parent how to create its child. + +For example, the structure of the code you want to test may follow this pattern: + +[!code-csharp[ParentStructure](../../examples/DocsExamples/Testkit/ParentSampleTest.cs?range=8-36)] + +###Introduce child to its parent +The first option is to avoid use of the `context.parent` function and create a child with a custom parent by passing an explicit reference to its parent instead. + +[!code-csharp[DependentChild](../../examples/DocsExamples/Testkit/ParentSampleTest.cs?range=39-52)] + +###Using a fabricated parent +If you prefer to avoid modifying the parent or child constructor you can create a fabricated parent in your test. This, however, does not enable you to test the parent actor in isolation. + +[!code-csharp[FabrikatedParent](../../examples/DocsExamples/Testkit/ParentSampleTest.cs?range=58-80)] + +###Externalize child making from the parent +Alternatively, you can tell the parent how to create its child. There are two ways to do this: by giving it a `Props` object or by giving it a function which takes care of creating the child actor: + +[!code-csharp[FabrikatedParent](../../examples/DocsExamples/Testkit/ParentSampleTest.cs?range=83-102)] + +Creating the Props is straightforward and the function may look like this in your test code: + +```csharp + Func maker = (ctx) => probe.Ref; + var parent = Sys.ActorOf(Props.Create(maker)); +``` + +And like this in your application code: + +```csharp + Func maker = (ctx) => ctx.ActorOf(Props.Create()) + var parent = Sys.ActorOf(Props.Create(maker)); +``` + +Which of these methods is the best depends on what is most important to test. The most generic option is to create the parent actor by passing it a function that is responsible for the Actor creation, but the fabricated parent is often sufficient. + +##CallingThreadDispatcher The `CallingThreadDispatcher` serves good purposes in unit testing, as described above, but originally it was conceived in order to allow contiguous stack traces to be generated in case of an error. As this special dispatcher runs everything which would normally be queued directly on the current thread, the full history of a message's processing chain is recorded on the call stack, so long as all intervening actors run on this dispatcher. @@ -208,4 +248,107 @@ akka { } } } -``` \ No newline at end of file +``` + +##Configuration +There are several configuration properties for the TestKit module, please refer to the [reference configuration](https://github.com/akkadotnet/akka.net/blob/master/src/core/Akka.TestKit/Configs/TestScheduler.conf) + +TODO describe how to pass custom config + +##Synchronous Testing: TestActorRef + +Testing the business logic inside `Actor` classes can be divided into two parts: first, each atomic operation must work in isolation, then sequences of incoming events must be processed correctly, even in the presence of some possible variability in the ordering of events. The former is the primary use case for single-threaded unit testing, while the latter can only be verified in integration tests. + +Normally, the `IActorRef` shields the underlying `Actor` instance from the outside, the only communications channel is the actor's mailbox. This restriction is an impediment to unit testing, which led to the inception of the `TestActorRef`. This special type of reference is designed specifically for test purposes and allows access to the actor in two ways: either by obtaining a reference to the underlying actor instance, or by invoking or querying the actor's behaviour (receive). Each one warrants its own section below. + +> [!NOTE] +> It is highly recommended to stick to traditional behavioural testing (using messaging to ask the `Actor` to reply with the state you want to run assertions against), instead of using `TestActorRef` whenever possible. + +## Obtaining a Reference to an Actor +Having access to the actual `Actor` object allows application of all traditional unit testing techniques on the contained methods. Obtaining a reference is done like this: + +```csharp + var props = Props.Create(); + var myTestActor = new TestActorRef(Sys, props, null, "testA"); + MyActor myActor = myTestActor.UnderlyingActor; +``` + +Since `TestActorRef` is generic in the actor type it returns the underlying actor with its proper static type. From this point on you may bring any unit testing tool to bear on your actor as usual. + +##Testing Finite State Machines +If your actor under test is a `FSM`, you may use the special `TestFSMRef` which offers all features of a normal `TestActorRef` and in addition allows access to the internal state: + +```csharp +var fsm = new TestFSMRef(); + +Assert.True(fsm.StateName == 1); +Assert.True(fsm.StateData == ""); + +fsm.Tell("go"); //being a TestActorRef, this runs on the CallingThreadDispatcher + +Assert.True(fsm.StateName == 2); +Assert.True(fsm.StateData == "go"); + +fsm.SetState(1); +Assert.True(fsm.StateName == 1); + +Assert.False(fsm.IsTimerActive("test")); +fsm.SetTimer("test",12, 10.Milliseconds(), true); +Assert.True(fsm.IsTimerActive("test")); +fsm.CancelTimer("test"); +Assert.False(fsm.IsTimerActive("test")); +``` + +All methods shown above directly access the FSM state without any synchronization; this is perfectly alright if the `CallingThreadDispatcher` is used and no other threads are involved, but it may lead to surprises if you were to actually exercise timer events, because those are executed on the `Scheduler` thread. + +##Testing the Actor's behavior +When the dispatcher invokes the processing behavior of an actor on a message, it actually calls apply on the current behavior registered for the actor. This starts out with the return value of the declared receive method, but it may also be changed using become and unbecome in response to external messages. All of this contributes to the overall actor behavior and it does not lend itself to easy testing on the `Actor` itself. Therefore the TestActorRef offers a different mode of operation to complement the `Actor` testing: it supports all operations also valid on normal `IActorRef`. Messages sent to the actor are processed synchronously on the current thread and answers may be sent back as usual. This trick is made possible by the `CallingThreadDispatcher` described below; this dispatcher is set implicitly for any actor instantiated into a `TestActorRef`. +```csharp +var props = Props.Create(); +var myTestActor = new TestActorRef(Sys, props, null, "testB"); +Task future = myTestActor.Ask("say42", TimeSpan.FromMilliseconds(3000)); +Assert.True(future.IsCompleted); +Assert.Equal(42, await future); +``` +As the `TestActorRef` is a subclass of `LocalActorRef` with a few special extras, also aspects like supervision and restarting work properly, but beware that execution is only strictly synchronous as long as all actors involved use the `CallingThreadDispatcher`. As soon as you add elements which include more sophisticated scheduling you leave the realm of unit testing as you then need to think about asynchronicity again (in most cases the problem will be to wait until the desired effect had a chance to happen). + +One more special aspect which is overridden for single-threaded tests is the `ReceiveTimeout`, as including that would entail asynchronous queuing of `ReceiveTimeout` messages, violating the synchronous contract. + +### The Way In-Between: Expecting Exceptions +If you want to test the actor behavior, including hotswapping, but without involving a dispatcher and without having the `TestActorRef` swallow any thrown exceptions, then there is another mode available for you: just use the receive method on `TestActorRef`, which will be forwarded to the underlying actor: +```csharp +var props = Props.Create(); +var myTestActor = new TestActorRef(Sys, props, null, "testB"); +try +{ + myTestActor.Receive(new Exception("expected")); +} +catch (Exception e) +{ + Assert.Equal("expected", e.Message); +} +``` + +##EventFilters + +EventFilters are a tool use can use to scan and expect for LogEvents generated by your actors. Typically these are generated by custom calls on the `Context.GetLogger()` object, when you log something. +However DeadLetter messages and Exceptions ultimately also result in a `LogEvent` message being generated. + +These are all things that can be intercepted, and asserted upon using the `EventFilter`. +An example of how you can get a reference to the `EventFilter` +```csharp + var filter = CreateEventFilter(Sys); + + filter.DeadLetter().ExpectOne(() => + { + //cause a message to be deadlettered here + + }); + + filter.Custom(logEvent => logEvent is Error && (string)logEvent.Message == "whatever").ExpectOne(() => + { + Log.Error("whatever"); + }); + + filter.Exception().ExpectOne(() => Log.Error(new MyException(), "the message")); +``` diff --git a/docs/articles/actors/untyped-actor-api.md b/docs/articles/actors/untyped-actor-api.md index 08d5d09a9ee..7a3b3db48a2 100644 --- a/docs/articles/actors/untyped-actor-api.md +++ b/docs/articles/actors/untyped-actor-api.md @@ -300,7 +300,7 @@ Messages can be sent via the `ActorSelection` and the path of the `ActorSelectio To acquire an `IActorRef` for an `ActorSelection` you need to send a message to the selection and use the `Sender` reference of the reply from the actor. There is a built-in `Identify` message that all Actors will understand and automatically reply to with a `ActorIdentity` message containing the `IActorRef`. This message is handled specially by the actors which are traversed in the sense that if a concrete name lookup fails (i.e. a non-wildcard path element does not correspond to a live actor) then a negative result is generated. Please note that this does not mean that delivery of that reply is guaranteed, it still is a normal message. -[!code-csharp[Main](../../examples/Actors/UntypedActorAPI/Follower.cs?range=8-41)] +[!code-csharp[Main](../../examples/DocsExamples/Actors/UntypedActorAPI/Follower.cs?range=8-41)] You can also acquire an `IActorRef` for an `ActorSelection` with the `ResolveOne` method of the `ActorSelection`. It returns a Task of the matching `IActorRef` if such an actor exists. It is completed with failure `akka.actor.ActorNotFound` if no such actor exists or the identification didn't complete within the supplied timeout. diff --git a/docs/articles/clustering/cluster-client.md b/docs/articles/clustering/cluster-client.md index 28903536532..509f80ed6ec 100644 --- a/docs/articles/clustering/cluster-client.md +++ b/docs/articles/clustering/cluster-client.md @@ -99,11 +99,11 @@ akka.extensions = ["Akka.Cluster.Tools.Client.ClusterClientReceptionist"] ## Events As mentioned earlier, both the `ClusterClient` and `ClusterClientReceptionist` emit events that can be subscribed to. The following code snippet declares an actor that will receive notifications on contact points (addresses to the available receptionists), as they become available. The code illustrates subscribing to the events and receiving the `ClusterClient` initial state. -[!code-csharp[Main](../../examples/Networking/ClusterClient/ClientListener.cs?range=7-47)] +[!code-csharp[Main](../../examples/DocsExamples/Networking/ClusterClient/ClientListener.cs?range=7-47)] Similarly we can have an actor that behaves in a similar fashion for learning what cluster clients contact a `ClusterClientReceptionist`: -[!code-csharp[Main](../../examples/Networking/ClusterClient/ReceptionistListener.cs?range=7-47)] +[!code-csharp[Main](../../examples/DocsExamples/Networking/ClusterClient/ReceptionistListener.cs?range=7-47)] ## Configuration The `ClusterClientReceptionist` extension (or `ClusterReceptionistSettings`) can be configured with the following properties: diff --git a/docs/articles/clustering/cluster-configuration.md b/docs/articles/clustering/cluster-configuration.md index 8a33b103c45..89404649e4b 100644 --- a/docs/articles/clustering/cluster-configuration.md +++ b/docs/articles/clustering/cluster-configuration.md @@ -20,7 +20,7 @@ You can see all of these options being used in the following HOCON: akka { actor.provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster" remote { - helios.tcp { + dot-netty.tcp { port = 8081 hostname = localhost } @@ -45,7 +45,7 @@ If you want to specify a cluster-wide minimum size, then we need to set the `clu akka { actor.provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster" remote { - helios.tcp { + dot-netty.tcp { port = 8081 hostname = localhost } @@ -64,9 +64,9 @@ If you want to delay nodes of a specific role from being marked as up until a ce ```xml akka { - actor.provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster" + actor.provider = cluster remote { - helios.tcp { + dot-netty.tcp { port = 8081 hostname = localhost } diff --git a/docs/articles/clustering/cluster-overview.md b/docs/articles/clustering/cluster-overview.md index 57d37878e51..223a4a787d0 100644 --- a/docs/articles/clustering/cluster-overview.md +++ b/docs/articles/clustering/cluster-overview.md @@ -86,7 +86,7 @@ Once you've installed Akka.Cluster, we need to update our HOCON configuration to akka { actor.provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster" remote { - helios.tcp { + dot-netty.tcp { port = 8081 hostname = localhost } @@ -109,7 +109,7 @@ You can, and should, specify multiple seed nodes inside this field - and seed no akka { actor.provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster" remote { - helios.tcp { + dot-netty.tcp { port = 0 #let os pick random port hostname = localhost } @@ -155,6 +155,7 @@ A node is a logical member of a cluster. A node is defined by the address at whi ### Seed Nodes A seed node is a well-known contact point that a new node must contact in order to join the cluster. Seed nodes function as the service-discovery mechanism of Akka.Cluster. +> [!NOTE] > [Lighthouse](https://github.com/petabridge/lighthouse) is a pre-built, dedicated seed node tool that you can use. It's extremely lightweight and only needs to be upgraded when Akka.Cluster itself is upgraded. If you're hosted on a platform like Azure or AWS, you can also tap into the platform-specific APIs to accomplish the same effect. ## How a Cluster Forms @@ -203,9 +204,11 @@ The cluster leader is chosen by a leader election algorithm that randomly picks Each role within the cluster also has a leader, just for that role. Its primary responsibility is enforcing a minimum number of "up" members within the role (if specified in the [cluster config](cluster-configuration.md)). ### Reachability -Nodes send each other heartbeats on an ongoing basis. If a node misses enough heartbeats, this will trigger `unreachable` gossip messages from its peers. +Nodes send each other heartbeats on an ongoing basis. If a node misses enough heartbeats, this will trigger `unreachable` gossip messages from its peers. The leader will wait for the node to either become reachable again, restart or get downed. Until that happens, the cluster is not in a consistent state and the leader indicates that it is unable to perform its duties. If the gossip from a quorum of cluster nodes agree that the node is unreachable ("convergence"), the leader will mark it as down and begin removing the node from the cluster. You can control how long the cluster waits for unreachable nodes through the auto-down-unreachable-after setting. + +When marked as unreachable, the node can restart and join the cluster again, however the association will only be formed if that node is identified as the same node that became unreachable. If you use dynamic addressing (port 0), starting a node again might result in a different port being assigned upon restart. The result of that is that the cluster remains in an inconsistent state, waiting to the unreachable node to either become reachable or get downed. -If the gossip from a quorum of cluster nodes agree that the node is unreachable ("convergence"), the leader will mark it as down and begin removing the node from the cluster. +A node might also exit the cluster gracefully, preventing it from being marked as unreachable in the first place. Akka.net uses IDowningProvider to take the nodes through all the stages of existing the cluster. Starting in Akka.NET 1.2 [CoordinatedShutdown](https://github.com/akkadotnet/akka.net/releases/tag/v1.2) was introduced allowing the user to easily invoke that mechanism. ## Location Transparency [Location transparency](xref:location-transparency) is the underlying principle powering all of Akka.Remote and Akka.Cluster. The key point is that in a cluster, it's entirely possible that the actors you interface with to do work can be living on any node in the cluster... and you don't have to worry about which one. diff --git a/docs/articles/concepts/addressing.md b/docs/articles/concepts/addressing.md index 4be4131b67a..eb0a7a3583e 100644 --- a/docs/articles/concepts/addressing.md +++ b/docs/articles/concepts/addressing.md @@ -11,7 +11,7 @@ This chapter describes how actors are identified and located within a possibly d The above image displays the relationship between the most important entities within an actor system, please read on for the details. -##What is an Actor Reference? +## What is an Actor Reference? An actor reference is a subtype of `ActorRef`, whose foremost purpose is to support sending messages to the actor it represents. Each actor has access to its canonical (local) reference through the `Self` property; this reference is also included as sender reference by default for all messages sent to other actors. Conversely, during message processing the actor has access to a reference representing the sender of the current message through the sender method. There are several different types of actor references that are supported depending on the configuration of the actor system: diff --git a/docs/articles/concepts/configuration.md b/docs/articles/concepts/configuration.md index b37699a00b7..a26d761b368 100644 --- a/docs/articles/concepts/configuration.md +++ b/docs/articles/concepts/configuration.md @@ -26,13 +26,12 @@ For example, let's configure an `ActorSystem` with HOCON: ```csharp var config = ConfigurationFactory.ParseString(@" -akka.remote.helios.tcp { - transport-class = - ""Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote"" - transport-protocol = tcp - port = 8091 - hostname = ""127.0.0.1"" - }"); +akka.remote.dot-netty.tcp { + transport-class = ""Akka.Remote.Transport.DotNetty.DotNettyTransport, Akka.Remote"" + transport-protocol = tcp + port = 8091 + hostname = ""127.0.0.1"" +}"); var system = ActorSystem.Create("MyActorSystem", config); ``` @@ -63,8 +62,7 @@ Here's an example of using HOCON inside `App.config`: -
+
@@ -77,7 +75,7 @@ Here's an example of using HOCON inside `App.config`: loglevel = ERROR # this config section will be referenced as akka.actor actor { - provider = "Akka.Remote.RemoteActorRefProvider, Akka.Remote" + provider = remote debug { receive = on autoreceive = on @@ -88,9 +86,8 @@ Here's an example of using HOCON inside `App.config`: } # here we're configuring the Akka.Remote module remote { - helios.tcp { - transport-class = - "Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote" + dot-netty.tcp { + transport-class = "Akka.Remote.Transport.DotNetty.DotNettyTransport, Akka.Remote" #applied-adapters = [] transport-protocol = tcp port = 8091 @@ -107,7 +104,7 @@ Here's an example of using HOCON inside `App.config`: And then we can load this configuration section into our `ActorSystem` via the following code: ```csharp -var system = ActorSystem.Create("Mysystem"); //automatically loads App/Web.config +var system = ActorSystem.Create("MySystem"); //automatically loads App/Web.config ``` #### HOCON Configuration Supports Fallbacks diff --git a/docs/articles/concepts/message-delivery-reliability.md b/docs/articles/concepts/message-delivery-reliability.md index 9afbb8b417d..a69c8fc16c9 100644 --- a/docs/articles/concepts/message-delivery-reliability.md +++ b/docs/articles/concepts/message-delivery-reliability.md @@ -315,7 +315,7 @@ The dead letter service follows the same rules with respect to delivery guarantees as all other message sends, hence it cannot be used to implement guaranteed delivery. -###How do I Receive Dead Letters? +### How do I Receive Dead Letters? An actor can subscribe to class `Akka.Actor.DeadLetter` on the event stream, see [Event stream](xref:event-bus) for how to do that. The subscribed actor will then receive all dead diff --git a/docs/articles/intro/getting-started.md b/docs/articles/intro/getting-started.md deleted file mode 100644 index 371ea531671..00000000000 --- a/docs/articles/intro/getting-started.md +++ /dev/null @@ -1,176 +0,0 @@ ---- -layout: docs.hbs -title: Getting started ---- -# Getting started with Akka.NET - -This tutorial is intended to give an introduction to using Akka.NET by creating a simple greeter actor using C#. - -## Set up your project - -Start visual studio and create a new C# Console Application. -Once we have our console application, we need to open up the Package Manager Console and type: - -```PM -PM> Install-Package Akka -``` - -Then we need to add the relevant using statements: - -```csharp -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -//Add these two lines -using Akka; -using Akka.Actor; - -namespace ConsoleApplication11 -{ - class Program - { - static void Main(string[] args) - { - } - } -} -``` - -## Create your first actor - -First, we need to create a message type that our actor will respond to: - -```csharp -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using Akka; -using Akka.Actor; - -namespace ConsoleApplication11 -{ - // Create an (immutable) message type that your actor will respond to - public class Greet - { - public Greet(string who) - { - Who = who; - } - public string Who { get;private set; } - } - - class Program - { - static void Main(string[] args) - { - } - } -} -``` - -Once we have the message type, we can create our actor: -```csharp -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using Akka; -using Akka.Actor; - -namespace ConsoleApplication11 -{ - public class Greet - { - public Greet(string who) - { - Who = who; - } - public string Who { get;private set; } - } - - // Create the actor class - public class GreetingActor : ReceiveActor - { - public GreetingActor() - { - // Tell the actor to respond - // to the Greet message - Receive(greet => - Console.WriteLine("Hello {0}", greet.Who)); - } - } - - class Program - { - static void Main(string[] args) - { - } - } -} -``` - -Now it's time to consume our actor, we do so by creating an `ActorSystem` and calling `ActorOf` - -```csharp -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using Akka; -using Akka.Actor; - -namespace ConsoleApplication11 -{ - public class Greet - { - public Greet(string who) - { - Who = who; - } - public string Who { get;private set; } - } - - public class GreetingActor : ReceiveActor - { - public GreetingActor() - { - Receive(greet => - Console.WriteLine("Hello {0}", greet.Who)); - } - } - - class Program - { - static void Main(string[] args) - { - // Create a new actor system (a container for your actors) - var system = ActorSystem.Create("MySystem"); - - // Create your actor and get a reference to it. - // This will be an "ActorRef", which is not a - // reference to the actual actor instance - // but rather a client or proxy to it. - var greeter = system.ActorOf("greeter"); - - // Send a message to the actor - greeter.Tell(new Greet("World")); - - // This prevents the app from exiting - // before the async work is done - Console.ReadLine(); - } - } -} -``` - -That is it, your actor is now ready to consume messages sent from any number of calling threads. diff --git a/docs/articles/intro/the-obligatory-hello-world.md b/docs/articles/intro/the-obligatory-hello-world.md deleted file mode 100644 index 656d6ba8d8f..00000000000 --- a/docs/articles/intro/the-obligatory-hello-world.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -layout: docs.hbs -title: The Obligatory Hello World ---- -# The Obligatory Hello World -This example shows how to define and consume actors in both C# and F# - -## Hello World using the C# API -#### Define a message: -```csharp -// Create an (immutable) message type that your actor will respond to -public class Greet -{ - public Greet(string who) - { - Who = who; - } - public string Who { get;private set; } -} -``` -#### Define your actor using the `ReceiveActor` API -```csharp -// Create the actor class -public class GreetingActor : ReceiveActor -{ - public GreetingActor() - { - Receive(greet => Console.WriteLine("Hello {0}", greet.Who)); - } -} -``` - -#### ..or using the `TypedActor` API -```csharp -public class GreetingActor : TypedActor , IHandle -{ - public void Handle(Greet greet) - { - Console.WriteLine("Hello {0}!", greet.Who); - } -} -``` - - -#### Usage: -```csharp -// Create a new actor system (a container for your actors) -var system = ActorSystem.Create("MySystem"); - -// Create your actor and get a reference to it. -// This will be an "IActorRef", which is not a reference to the actual actor -// instance but rather a client or proxy to it. -var greeter = system.ActorOf("greeter"); - -// Send a message to the actor. -greeter.Tell(new Greet("World")); - -// This prevents the app from exiting -// before the async work is done. -Console.ReadLine(); -``` -See also: -- [[Untyped actors]]. -- [[Typed actors]]. - -## Hello World using the F# API - -```fsharp -// Create an (immutable) message type that your actor will respond to -type Greet = Greet of string - -let system = ActorSystem.Create "MySystem" - -// Use F# computation expression with tail-recursive loop -// to create an actor message handler and return a reference -let greeter = spawn system "greeter" <| fun mailbox -> - let rec loop() = actor { - let! msg = mailbox.Receive() - match msg with - | Greet who -> printf "Hello, %s!\n" who - return! loop() } - loop() - -greeter Does the root guardian (the root path `/`) have a parent? As it turns out, it has. This special entity is called +> the "Bubble-Walker". This special entity is invisible for the user and only has uses internally. + +### Structure of an IActorRef and Paths of Actors + +The easiest way to see this in action is to simply print `IActorRef` instances. In this small experiment, we print +the reference of the first actor we create and then we create a child of this actor, and print its reference. We have +already created actors with `System.ActorOf()`, which creates an actor under `/user` directly. We call this kind +of actors _top level_, even though in practice they are not on the top of the hierarchy, only on the top of the +_user defined_ hierarchy. Since in practice we usually concern ourselves about actors under `/user` this is still a +convenient terminology, and we will stick to it. + +Creating a non-top-level actor is possible from any actor, by invoking `Context.ActorOf()` which has the exact same +signature as its top-level counterpart. This is how it looks like in practice: + +[!code-csharp[Main](../../examples/Tutorials/Tutorial1/ActorHierarchyExperiments.cs?name=print-refs)] +[!code-csharp[Main](../../examples/Tutorials/Tutorial1/ActorHierarchyExperiments.cs?name=print-refs2)] + +We see that the following two lines are printed + +``` +First : Actor[akka://testSystem/user/first-actor#1053618476] +Second: Actor[akka://testSystem/user/first-actor/second-actor#-1544706041] +``` + +First, we notice that all of the paths start with `akka://testSystem/`. Since all actor references are valid URLs, there +is a protocol field needed, which is `akka://` in the case of actors. Then, just like on the World Wide Web, the system +is identified. In our case, this is `testSystem`, but could be any other name (if remote communication between multiple +systems is enabled this name is the hostname of the system so other systems can find it on the network). Our two actors, +as we have discussed before, live under user, and form a hierarchy: + + * `akka://testSystem/user/first-actor` is the first actor we created, which lives directly under the user guardian, + `/user` + * `akka://testSystem/user/first-actor/second-actor` is the second actor we created, using `Context.ActorOf`. As we + see it lives directly under the first actor. + +The last part of the actor reference, like `#1053618476` is a unique identifier of the actor living under the path. +This is usually not something the user needs to be concerned with, and we leave the discussion of this field for later. + +### Hierarchy and Lifecycle of Actors + +We have so far seen that actors are organized into a **strict hierarchy**. This hierarchy consists of a predefined +upper layer of three actors (the root guardian, the user guardian, and the system guardian), thereafter the user created +top-level actors (those directly living under `/user`) and the children of those. We now understand what the hierarchy +looks like, but there are some nagging unanswered questions: _Why do we need this hierarchy? What is it used for?_ + +The first use of the hierarchy is to manage the lifecycle of actors. Actors pop into existence when created, then later, +at user requests, they are stopped. Whenever an actor is stopped, all of its children are _recursively stopped_ too. +This is a very useful property and greatly simplifies cleaning up resources and avoiding resource leaks (like open +sockets files, etc.). In fact, one of the overlooked difficulties when dealing with low-level multi-threaded code is +the lifecycle management of various concurrent resources. + +Stopping an actor can be done by calling `Context.Stop(actorRef)`. **It is considered a bad practice to stop arbitrary +actors this way**. The recommended pattern is to call `Context.Stop(self)` inside an actor to stop itself, usually as +a response to some user defined stop message or when the actor is done with its job. + +The actor API exposes many lifecycle hooks that the actor implementation can override. The most commonly used are +`PreStart()` and `PostStop()`. + + * `PreStart()` is invoked after the actor has started but before it processes its first message. + * `PostStop()` is invoked just before the actor stops. No messages are processed after this point. + +Again, we can try out all this with a simple experiment: + +[!code-csharp[Main](../../examples/Tutorials/Tutorial1/ActorHierarchyExperiments.cs?name=start-stop)] +[!code-csharp[Main](../../examples/Tutorials/Tutorial1/ActorHierarchyExperiments.cs?name=start-stop2)] + +After running it, we get the output + +``` +first started +second started +second stopped +first stopped +``` + +We see that when we stopped actor `first` it recursively stopped actor `second` and thereafter it stopped itself. +This ordering is strict, _all_ `PostStop()` hooks of the children are called before the `PostStop()` hook of the parent +is called. + +The family of these lifecycle hooks is rich, and we recommend reading [the actor lifecycle](xref:untyped-actor-api#actor-lifecycle) section of the reference for all details. + +### Hierarchy and Failure Handling (Supervision) + +Parents and children are not only connected by their lifecycles. Whenever an actor fails (throws an exception or +an unhandled exception bubbles out from `receive`) it is temporarily suspended. The failure information is propagated +to the parent, which decides how to handle the exception caused by the child actor. The default _supervisor strategy_ is to +stop and restart the child. If you don't change the default strategy all failures result in a restart. We won't change +the default strategy in this simple experiment: + +[!code-csharp[Main](../../examples/Tutorials/Tutorial1/ActorHierarchyExperiments.cs?name=supervise)] +[!code-csharp[Main](../../examples/Tutorials/Tutorial1/ActorHierarchyExperiments.cs?name=supervise2)] + +After running the snippet, we see the following output on the console: + +``` +supervised actor started +supervised actor fails now +supervised actor stopped +[ERROR][05.06.2017 13:34:50][Thread 0003][akka://testSystem/user/supervising-actor/supervised-actor] I failed! +Cause: System.Exception: I failed! + at Tutorials.Tutorial1.SupervisedActor.OnReceive(Object message) + at Akka.Actor.UntypedActor.Receive(Object message) + at Akka.Actor.ActorBase.AroundReceive(Receive receive, Object message) + at Akka.Actor.ActorCell.ReceiveMessage(Object message) + at Akka.Actor.ActorCell.Invoke(Envelope envelope) +``` + +We see that after failure the actor is stopped and immediately started. We also see a log entry reporting the +exception that was handled, in this case, our test exception. In this example we use `PreStart()` and `PostStop()` hooks +which are the default to be called after and before restarts, so we cannot distinguish from inside the actor if it +was started for the first time or restarted. This is usually the right thing to do, the purpose of the restart is to +set the actor in a known-good state, which usually means a clean starting stage. **What actually happens though is +that the `PreRestart()` and `PostRestart()` methods are called which, if not overridden, by default delegate to +`PostStop()` and `PreStart()` respectively**. You can experiment with overriding these additional methods and see +how the output changes. + +For the impatient, we also recommend looking into the [supervision reference page](xref:supervision) for more in-depth +details. + +### The First Actor + +Actors are organized into a strict tree, where the lifecycle of every child is tied to the parent and where parents +are responsible for deciding the fate of failed children. At first, it might not be evident how to map our problem +to such a tree, but in practice, this is easier than it looks. All we need to do is to rewrite our architecture diagram +that contained nested boxes into a tree: + +![actor tree diagram of the architecture](/images/arch_tree_diagram.png) + +In simple terms, every component manages the lifecycle of the subcomponents. No subcomponent can outlive the parent +component. This is exactly how the actor hierarchy works. Furthermore, it is desirable that a component handles the failure +of its subcomponents. Together, these two desirable properties lead to the conclusion that the "contained-in" relationship of components should be mapped to the +"children-of" relationship of actors. + +The remaining question is how to map the top-level components to actors. It might be tempting to create the actors +representing the main components as top-level actors. We instead, recommend creating an explicit component that +represents the whole application. In other words, we will have a single top-level actor in our actor system and have +the main components as children of this actor. + +The first actor happens to be rather simple now, as we have not implemented any of the components yet. What is new +is that we have dropped using `Console.WriteLine()` and instead use `ILoggingAdapter` which allows us to use the +logging facility built into Akka.NET directly. Furthermore, we are using a recommended creational pattern for actors; define a static `Props()` method in the the actor: + +[!code-csharp[Main](../../examples/Tutorials/Tutorial1/IotSupervisor.cs?name=iot-supervisor)] + +All we need now is to tie this up with a class with the `main` entry point: + +[!code-csharp[Main](../../examples/Tutorials/Tutorial1/IotApp.cs?name=iot-app)] + +This application does very little for now, but we have the first actor in place and we are ready to extend it further. + +## What is next? + +In the following chapters we will grow the application step-by-step: + + 1. We will create the representation for a device + 2. We create the device management component + 3. We add query capabilities to device groups \ No newline at end of file diff --git a/docs/articles/intro/tutorial-2.md b/docs/articles/intro/tutorial-2.md new file mode 100644 index 00000000000..bd34ad35522 --- /dev/null +++ b/docs/articles/intro/tutorial-2.md @@ -0,0 +1,191 @@ +--- +uid: tutorial-2 +title: Part 2. The Device Actor +--- + +# Part 2: The Device Actor + +In part 1 we explained how to view actor systems _in the large_, i.e. how components should be represented, how +actors should be arranged in the hierarchy. In this part, we will look at actors _in the small_ by implementing an +actor with the most common conversational patterns. + +In particular, leaving the components aside for a while, we will implement an actor that represents a device. The +tasks of this actor will be rather simple: + + * Collect temperature measurements + * Report the last measured temperature if asked + +When working with objects we usually design our API as _interfaces_, which are basically a collection of abstract +methods to be filled out by the actual implementation. In the world of actors, the counterpart of interfaces is +protocols. While it is not possible to formalize general protocols in the programming language, we can formalize +its most basic elements: the messages. + +## The Query Protocol + +Just because a device have been started it does not mean that it has immediately a temperature measurement. Hence, we +need to account for the case where a temperature is not present in our protocol. This, fortunately, means that we +can test the query part of the actor without the write part present, as it can simply report an empty result. + +The protocol for obtaining the current temperature from the device actor is rather simple: + + 1. Wait for a request for the current temperature. + 2. Respond to the request with a reply containing the current temperature or an indication that it is not yet + available. + +We need two messages, one for the request, and one for the reply. A first attempt could look like this: + +[!code-csharp[Main](../../examples/Tutorials/Tutorial2/DeviceInProgress.cs?name=read-protocol-1)] + +This is a fine approach, but it limits the flexibility of the protocol. To understand why we need to talk +about message ordering and message delivery guarantees in general. + +## Message Ordering, Delivery Guarantees + +In order to give some context to the discussion below, consider an application which spans multiple network hosts. +The basic mechanism for communication is the same whether sending to an actor on the local CLR or to a remote actor, +but of course, there will be observable differences in the latency of delivery (possibly also depending on the bandwidth +of the network link and the message size) and the reliability. In the case of a remote message send there are +more steps involved which means that more can go wrong. Another aspect is that a local send will just pass a +reference to the message inside the same CLR, without any restrictions on the underlying object which is sent, +whereas a remote transport will place a limit on the message size. + +It is also important to keep in mind, that while sending inside the same CLR is significantly more reliable, if an +actor fails due to a programmer error while processing the message, the effect is basically the same as if a remote, +network request fails due to the remote host crashing while processing the message. Even though in both cases the +service is recovered after a while (the actor is restarted by its supervisor, the host is restarted by an operator +or by a monitoring system) individual requests are lost during the crash. **Writing your actors such that every +message could possibly be lost is the safe, pessimistic bet.** + +These are the rules in Akka.NET for message sends: + + * At-most-once delivery, i.e. no guaranteed delivery. + * Message ordering is maintained per sender, receiver pair. + +### What Does "at-most-once" Mean? + +When it comes to describing the semantics of a delivery mechanism, there are three basic categories: + + * **At-most-once delivery** means that for each message handed to the mechanism, that message is delivered zero or + one time; in more casual terms it means that messages may be lost, but never duplicated. + * **At-least-once delivery** means that for each message handed to the mechanism potentially multiple attempts are made + at delivering it, such that at least one succeeds; again, in more casual terms this means that messages may be duplicated but not lost. + * **Exactly-once delivery** means that for each message handed to the mechanism exactly one delivery is made to + the recipient; the message can neither be lost nor duplicated. + +The first one is the cheapest, highest performance, least implementation overhead because it can be done in a +fire-and-forget fashion without keeping the state at the sending end or in the transport mechanism. +The second one requires retries to counter transport losses, which means keeping the state at the sending end and +having an acknowledgment mechanism at the receiving end. The third is most expensive, and has consequently worst +performance: in addition to the second, it requires the state to be kept at the receiving end in order to filter out +duplicate deliveries. + +### Why No Guaranteed Delivery? + +At the core of the problem lies the question what exactly this guarantee shall mean, i.e. at which point does +the delivery considered to be guaranteed: + + 1. When the message is sent out on the network? + 2. When the message is received by the other host? + 3. When the message is put into the target actor's mailbox? + 4. When the message is starting to be processed by the target actor? + 5. When the message is processed successfully by the target actor? + +Most frameworks/protocols claiming guaranteed delivery actually provide something similar to point 4 and 5. While this +sounds fair, **is this actually useful?** To understand the implications, consider a simple, practical example: +a user attempts to place an order and we only want to claim that it has successfully processed once it is actually on +disk in the database containing orders. + +If we rely on the guarantees of such system it will report success as soon as the order has been submitted to the +internal API that has the responsibility to validate it, process it and put it into the database. Unfortunately, +immediately after the API has been invoked the following may happen: + + * The host can immediately crash. + * Deserialization can fail. + * Validation can fail. + * The database might be unavailable. + * A programming error might occur. + +The problem is that the **guarantee of delivery** does not translate to the **domain level guarantee**. We only want to +report success once the order has been actually fully processed and persisted. **The only entity that can report +success is the application itself, since only it has any understanding of the domain guarantees required. No generalized +framework can figure out the specifics of a particular domain and what is considered a success in that domain**. In +this particular example, we only want to signal success after a successful database write, where the database acknowledged +that the order is now safely stored. **For these reasons Akka.NET lifts the responsibilities of guarantees to the application +itself, i.e. you have to implement them yourself. On the other hand, you are in full control of the guarantees that you want +to provide**. + +### Message Ordering + +The rule is that for a given pair of actors, messages sent directly from the first to the second will not be +received out-of-order. The word directly emphasizes that this guarantee only applies when sending with the tell +operator directly to the final destination, but not when employing mediators. + +If: + + * Actor `A1` sends messages `M1`, `M2`, `M3` to `A2`. + * Actor `A3` sends messages `M4`, `M5`, `M6` to `A2`. + +This means that: + + * If `M1` is delivered it must be delivered before `M2` and `M3`. + * If `M2` is delivered it must be delivered before `M3`. + * If `M4` is delivered it must be delivered before `M5` and `M6`. + * If `M5` is delivered it must be delivered before `M6`. + * `A2` can see messages from `A1` interleaved with messages from `A3`. + * Since there is no guaranteed delivery, any of the messages may be dropped, i.e. not arrive at `A2`. + +For the full details on delivery guarantees please refer to the [reference page](xref:message-delivery-reliability). + +### Revisiting the Query Protocol + +There is nothing wrong with our first query protocol but it limits our flexibility. If we want to implement resends +in the actor that queries our device actor (because of timed out requests) or want to query multiple actors it +can be helpful to put an additional query ID field in the message which helps us correlate requests with responses. + +Hence, we add one more field to our messages, so that an ID can be provided by the requester: + +[!code-csharp[Main](../../examples/Tutorials/Tutorial2/DeviceInProgress.cs?name=read-protocol-2)] + +Our device actor has the responsibility to use the same ID for the response of a given query. Now we can sketch +our device actor: + +[!code-csharp[Main](../../examples/Tutorials/Tutorial2/DeviceInProgress.cs?name=device-with-read)] + +We maintain the current temperature, initially set to `null`, and we simply report it back if queried. We also +added fields for the ID of the device and the group it belongs to, which we will use later. + +We can already write a simple test for this functionality @scala[(we use ScalaTest but any other test framework can be +used with the Akka.NET Testkit)]: + +[!code-csharp[Main](../../examples/Tutorials/Tutorial2/DeviceSpec.cs?name=device-read-test)] + +## The Write Protocol + +As a first attempt, we could model recording the current temperature in the device actor as a single message: + + * When a temperature record request is received, update the `currentTemperature` property. + +Such a message could possibly look like this: + +[!code-csharp[Main](../../examples/Tutorials/Tutorial2/DeviceInProgress.cs?name=write-protocol-1)] + +The problem with this approach is that the sender of the record temperature message can never be sure if the message +was processed or not. We have seen that Akka.NET does not guarantee delivery of these messages and leaves it to the +application to provide success notifications. In our case, we would like to send an acknowledgment to the sender +once we have updated our last temperature recording, e.g. `TemperatureRecorded`. +Just like in the case of temperature queries and responses, it is a good idea to include an ID field to provide maximum flexibility. + +Putting read and write protocol together, the device actor will look like this: + +[!code-csharp[Main](../../examples/Tutorials/Tutorial2/Device.cs?name=full-device)] + +We are also responsible for writing a new test case now, exercising both the read/query and write/record functionality +together: + +[!code-csharp[Main](../../examples/Tutorials/Tutorial2/DeviceSpec.cs?name=device-write-read-test)] + +## What is Next? + +So far, we have started designing our overall architecture, and we wrote our first actor directly corresponding to the +domain. We now have to create the component that is responsible for maintaining groups of devices and the device +actors themselves. \ No newline at end of file diff --git a/docs/articles/intro/tutorial-3.md b/docs/articles/intro/tutorial-3.md new file mode 100644 index 00000000000..1b496cd5818 --- /dev/null +++ b/docs/articles/intro/tutorial-3.md @@ -0,0 +1,211 @@ +--- +uid: tutorial-3 +title: Part 3. Device Groups and Manager +--- + +# Part 3: Device Groups and Manager + +In this chapter, we will integrate our device actors into a component that manages devices. When a new device comes +online, there is no actor representing it. We need to be able to ask the device manager component to create a new +device actor for us if necessary, in the required group (or return a reference to an already existing one). + +Since we keep our tutorial system to the bare minimum, we have no actual component that interfaces with the external +world via some networking protocol. For our exercise, we will just create the API necessary to integrate with such +a component in the future. In a final system, the steps for connecting a device would look like this: + + 1. The device connects through some protocol to our system. + 2. The component managing network connections accept the connection. + 3. The ID of the device and the ID of the group that it belongs is acquired. + 4. The device manager component is asked to create a group and device actor for the given IDs (or return an existing + one). + 5. The device actor (just been created or located) responds with an acknowledgment, at the same time exposing its + `IActorRef` directly (by being the sender of the acknowledgment). + 6. The networking component now uses the `IActorRef` of the device directly, avoiding going through the component. + +We are only concerned with steps 4 and 5 now. We will model the device manager component as an actor tree with three +levels: + +![device manager tree](/images/device_manager_tree.png) + + * The top level is the supervisor actor representing the component. It is also the entry point to look up or create + group and device actors. + * Device group actors are supervisors of the devices belonging to the group. Apart from supervising the device actors they + also provide extra services, like querying the temperature readings from all the devices available. + * Device actors manage all the interactions with the actual devices, storing temperature readings for example. + +When designing actor systems one of the main challenges is to decide on the granularity of the actors. For example, it +would be perfectly possible to have only a single actor maintaining all the groups and devices in `Dictionary`s for +example. It would be also reasonable to keep the groups as separate actors, but keep device state simply inside +the group actor. + +We chose this three-layered architecture for the following reasons: + + * Having groups as individual actors: + * Allows us to isolate failures happening in a group. If a programmer error would + happen in the single actor that keeps all state, it would be all wiped out once that actor is restarted affecting groups that are otherwise non-faulty. + * Simplifies the problem of querying all the devices belonging to a group (since it only contains state related + to the given group). + * Increases the parallelism of the system by allowing to query multiple groups concurrently. Since groups have + dedicated actors, all of them can run concurrently. + * Having devices as individual actors: + * Allows us to isolate failures happening in a device actor from the rest of the devices. + * Increases the parallelism of collecting temperature readings as actual network connections from different devices + can talk to the individual device actors directly, reducing contention points. + +In practice, a system can be organized in multiple ways, all depending on the characteristics of the interactions +between actors. + +The following guidelines help to arrive at the right granularity: + + * Prefer larger granularity to smaller. Introducing more fine-grained actors than needed causes more problems than + it solves. + * Prefer finer granularity if it enables higher concurrency in the system. + * Prefer finer granularity if actors need to handle complex conversations with other actors and hence have many + states. We will see a very good example for this in the next chapter. + * Prefer finer granularity if there is too much state to keep around in one place compared to dividing into smaller + actors. + * Prefer finer granularity if the current actor has multiple unrelated responsibilities that can fail and restored + individually. + + +## The Registration Protocol + +As the first step, we need to design the protocol for registering a device and create an actor that will be responsible +for it. This protocol will be provided by the `DeviceManager` component itself because that is the only actor that +is known up front: device groups and device actors are created on-demand. The steps of registering a device are the following: + + 1. DeviceManager receives the request to track a device for a given group and device. + 2. If the manager already has an actor for the device group, it forwards the request to it. Otherwise, it first creates + a new one and then forwards the request. + 3. The DeviceGroup receives the request to register an actor for the given device. + 4. If the group already has an actor for the device, it forwards the request to it. Otherwise, it first creates + a new one and then forwards the request. + 5. The device actor receives the request and acknowledges it to the original sender. Since the device actor is the sender of + the acknowledgment, the receiver, i.e. the device, will be able to learn its `IActorRef` and send direct messages to its device actor in the future. + +Now that the steps are defined, we only need to define the messages that we will use to communicate requests and +their acknowledgement: + +[!code-csharp[DeviceManager.scala](../../examples/Tutorials/Tutorial3/DeviceManager.cs?name=device-manager-msgs)] + +As you see, in this case, we have not included a request ID field in the messages. Since registration is usually happening +once, at the component that connects the system to some network protocol, we will usually have no use for the ID. +Nevertheless, it is a good exercise to add this ID. + +## Add Registration Support to Device Actor + +We start implementing the protocol from the bottom first. In practice, both a top-down and bottom-up approach can +work, but in our case, we benefit from the bottom-up approach as it allows us to immediately write tests for the +new features without mocking out parts. + +At the bottom of our hierarchy are the `Device` actors. Their job in this registration process is rather simple, just reply to the +registration request with an acknowledgment to the sender. *We will assume that the sender of the registration +message is preserved in the upper layers.* We will show you in the next section how this can be achieved. + +We also add a safeguard against requests that come with a mismatched group or device ID. This is how the resulting +the code looks like: + +[!code-csharp[Device.scala](../../examples/Tutorials/Tutorial3/Device.cs?name=device-with-register)] + +We should not leave features untested, so we immediately write two new test cases, one exercising successful +registration, the other testing the case when IDs don't match: + +> [!NOTE] +> We used the `ExpectNoMsg()` helper method from `TestProbe`. This assertion waits until the defined time-limit +and fails if it receives any messages during this period. If no messages are received during the waiting period the +assertion passes. It is usually a good idea to keep these timeouts low (but not too low) because they add significant +test execution time otherwise. + +[!code-csharp[DeviceSpec.scala](../../examples/Tutorials/Tutorial3/DeviceSpec.cs?name=device-registration-tests)] + +## Device Group + +We are done with the registration support at the device level, now we have to implement it at the group level. A group +has more work to do when it comes to registrations. It must either forward the request to an existing child, or it +should create one. To be able to look up child actors by their device IDs we will use a `Dictionary`. + +We also want to keep the original sender of the request so that our device actor can reply directly. This is possible +by using `Forward` instead of the `Tell` operator. The only difference between the two is that `Forward` keeps the original +sender while `Tell` always sets the sender to be the current actor. Just like with our device actor, we ensure that we don't +respond to wrong group IDs: + +[!code-csharp[DeviceGroup.scala](../../examples/Tutorials/Tutorial3/DeviceGroupInProgress.cs?name=device-group-register)] + +Just as we did with the device, we test this new functionality. We also test that the actors returned for the two +different IDs are actually different, and we also attempt to record a temperature reading for each of the devices +to see if the actors are responding. + +[!code-csharp[DeviceGroupSpec.scala](../../examples/Tutorials/Tutorial3/DeviceGroupSpec.cs?name=device-group-test-registration)] + +It might be, that a device actor already exists for the registration request. In this case, we would like to use +the existing actor instead of a new one. We have not tested this yet, so we need to fix this: + +[!code-csharp[DeviceGroupSpec.scala](../../examples/Tutorials/Tutorial3/DeviceGroupSpec.cs?name=device-group-test3)] + +So far, we have implemented everything for registering device actors in the group. Devices come and go, however, so +we will need a way to remove those from the `Dictionary`. We will assume that when a device is removed, its corresponding device actor +is simply stopped. We need some way for the parent to be notified when one of the device actors are stopped. Unfortunately, +supervision will not help because it is used for error scenarios, not graceful stopping. + +There is a feature in Akka.NET that is exactly what we need here. It is possible for an actor to _watch_ another actor +and be notified if the other actor is stopped. This feature is called _Death Watch_ and it is an important tool for +any Akka.NET application. Unlike supervision, watching is not limited to parent-child relationships, any actor can watch +any other actor given its `IActorRef`. After a watched actor stops, the watcher receives a `Terminated(ref)` message +which also contains the reference to the watched actor. The watcher can either handle this message explicitly or, if +it does not handle it directly it will fail with a `DeathPactException`. This latter is useful if the actor cannot +longer perform its duties after its collaborator actor has been stopped. In our case, the group should still function +after one device have been stopped, so we need to handle this message. The steps we need to follow are the following: + + 1. Whenever we create a new device actor, we must also watch it. + 2. When we are notified that a device actor has been stopped we also need to remove it from the `Dictionary` which maps + devices to device actors. + +Unfortunately, the `Terminated` message contains only contains the `IActorRef` of the child actor but we do not know +its ID, which we need to remove it from the map of existing device to device actor mappings. To be able to do this removal, we +need to introduce another placeholder, `Dictionary`, that allow us to find out the device ID corresponding to a given `IActorRef`. Putting +this together the result is: + +[!code-csharp[DeviceGroup.scala](../../examples/Tutorials/Tutorial3/DeviceGroupInProgress.cs?name=device-group-remove)] + +So far we have no means to get what devices the group device actor keeps track of and, therefore, we cannot test our +new functionality yet. To make it testable, we add a new query capability `RequestDeviceList` that simply lists the currently active +device IDs: + +[!code-csharp[DeviceGroup.scala](../../examples/Tutorials/Tutorial3/DeviceGroup.cs?name=device-group-full)] + +We almost have everything to test the removal of devices. What is missing is: + + * Stopping a device actor from our test case, from the outside: any actor can be stopped by simply sending a special + the built-in message, `PoisonPill`, which instructs the actor to stop. + * Be notified once the device actor is stopped: we can use the _Death Watch_ facility for this purpose, too. Thankfully + the `TestProbe` has two messages that we can easily use, `Watch()` to watch a specific actor, and `ExpectTerminated` + to assert that the watched actor has been terminated. + +We add two more test cases now. In the first, we just test that we get back the list of proper IDs once we have added +a few devices. The second test case makes sure that the device ID is properly removed after the device actor has + been stopped: + +[!code-csharp[DeviceGroupSpec.scala](../../examples/Tutorials/Tutorial3/DeviceGroupSpec.cs?name=device-group-list-terminate-test)] + +## Device Manager + +The only part that remains now is the entry point for our device manager component. This actor is very similar to +the device group actor, with the only difference that it creates device group actors instead of device actors: + +[!code-csharp[DeviceManager.scala](../../examples/Tutorials/Tutorial3/DeviceManager.cs?name=device-manager-full)] + +We leave tests of the device manager as an exercise as it is very similar to the tests we have written for the group +actor. + +## What is Next? + +We have now a hierarchical component for registering and tracking devices and recording measurements. We have seen +some conversation patterns like: + + * Request-respond (for temperature recordings). + * Delegate-respond (for registration of devices). + * Create-watch-terminate (for creating the group and device actor as children). + +In the next chapter, we will introduce group query capabilities, which will establish a new conversation pattern of +scatter-gather. In particular, we will implement the functionality that allows users to query the status of all +the devices belonging to a group. \ No newline at end of file diff --git a/docs/articles/intro/tutorial-4.md b/docs/articles/intro/tutorial-4.md new file mode 100644 index 00000000000..09ade3f373e --- /dev/null +++ b/docs/articles/intro/tutorial-4.md @@ -0,0 +1,207 @@ +--- +uid: tutorial-4 +title: Part 4. Querying a Group of Devices +--- + +# Part 4: Querying a Group of Devices + +The conversational patterns we have seen so far were simple in the sense that they required no or little state to be kept in the +actor that is only relevant to the conversation. Our device actors either simply returned a reading, which required no +state change, recorded a temperature, which was required an update of a single field, or in the most complex case, +managing groups and devices, we had to add or remove simple entries from a map. + +In this chapter, we will see a more complex example. Our goal is to add a new service to the group device actor, one which +allows querying the temperature from all running devices. Let us start by investigating how we want our query API to +behave. + +The very first issue we face is that the set of devices is dynamic, and each device is represented by an actor that +can stop at any time. At the beginning of the query, we need to ask all of the device actors for the current temperature +that we know about. However, during the lifecycle of the query: + + * A device actor may stop and not respond back with a temperature reading. + * A new device actor might start up, but we missed asking it for the current temperature. + +There are many approaches that can be taken to address these issues, but the important point is to settle on what is +the desired behavior. We will pick the following two guarantees: + + * When a query arrives at the group, the group actor takes a _snapshot_ of the existing device actors and will only + ask those for the temperature. Actors that are started _after_ the arrival of the query are simply ignored. + * When an actor stops during the query without answering (i.e. before all the actors we asked for the temperature + responded) we simply report back that fact to the sender of the query message. + +Apart from device actors coming and going dynamically, some actors might take a long time to answer, for example, because +they are stuck in an accidental infinite loop, or because they failed due to a bug and dropped our request. Ideally, +we would like to give a deadline to our query: + + * The query is considered completed if either all actors have responded (or confirmed being stopped), or we reach + the deadline. + +Given these decisions, and the fact that a device might not have a temperature to record, we can define four states +that each device can be in, according to the query: + + * It has a temperature available: `Temperature`. + * It has responded, but has no temperature available yet: `TemperatureNotAvailable`. + * It has stopped before answering: `DeviceNotAvailable`. + * It did not respond before the deadline: `DeviceTimedOut`. + +Summarizing these in message types we can add the following to `DeviceGroup`: + +[!code-csharp[DeviceGroup.cs](../../examples/Tutorials/Tutorial4/DeviceGroup.cs?name=query-protocol)] + +## Implementing the Query + +One of the approaches for implementing the query could be to add more code to the group device actor. While this is +possible, in practice this can be very cumbersome and error prone. When we start a query, we need to take a snapshot +of the devices present at the start of the query and start a timer so that we can enforce the deadline. Unfortunately, +during the time we execute a query _another query_ might just arrive. For this other query, of course, we need to keep +track of the exact same information but isolated from the previous query. This complicates the code and also poses +some problems. For example, we would need a data structure that maps the `IActorRef`s of the devices to the queries +that use that device, so that they can be notified when such a device terminates, i.e. a `Terminated` message is +received. + +There is a much simpler approach that is superior in every way, and it is the one we will implement. We will create +an actor that represents a _single query_ and which performs the tasks needed to complete the query on behalf of the +group actor. So far we have created actors that belonged to classical domain objects, but now, we will create an +actor that represents a process or task rather than an entity. This move keeps our group device actor simple and gives +us better ways to test the query capability in isolation. + +First, we need to design the lifecycle of our query actor. This consists of identifying its initial state, then +the first action to be taken by the actor, then, the cleanup if necessary. There are a few things the query should +need to be able to work: + + * The snapshot of active device actors to query, and their IDs. + * The requestID of the request that started the query (so we can include it in the reply). + * The `IActorRef` of the actor who sent the group actor the query. We will send the reply to this actor directly. + * A timeout parameter, how long the query should wait for replies. Keeping this as a parameter will simplify testing. + +Since we need to have a timeout for how long we are willing to wait for responses, it is time to introduce a new feature that we have +not used yet: timers. Akka has a built-in scheduler facility for this exact purpose. Using it is simple, the +`ScheduleTellOnceCancelable(time, actorRef, message, sender)` method will schedule the message `message` into the future by the +specified `time` and send it to the actor `actorRef`. To implement our query timeout we need to create a message +that represents the query timeout. We create a simple message `CollectionTimeout` without any parameters for +this purpose. The return value from `ScheduleTellOnceCancelable` is a `ICancellable` which can be used to cancel the timer +if the query finishes successfully in time. Getting the scheduler is possible from the `ActorSystem`, which, in turn, +is accessible from the actor's context: `Context.System.Scheduler`. + +At the start of the query, we need to ask each of the device actors for the current temperature. To be able to quickly +detect devices that stopped before they got the `ReadTemperature` message we will also watch each of the actors. This +way, we get `Terminated` messages for those that stop during the lifetime of the query, so we don't need to wait +until the timeout to mark these as not available. + +Putting together all these, the outline of our actor looks like this: + +[!code-csharp[DeviceGroupQueryInProgress.cs](../../examples/Tutorials/Tutorial4/DeviceGroupQueryInProgress.cs?name=query-outline)] + +The query actor, apart from the pending timer, has one stateful aspect about it: the actors that did not answer so far or, +from the other way around, the set of actors that have replied or stopped. One way to track this state is +to create a mutable field in the actor. There is another approach. It is also possible to change how +the actor responds to messages. By default, the `OnReceive` block defines the behavior of the actor, but it is possible +to change it, several times, during the life of the actor. This is possible by calling `Context.Become(newBehavior)` +where `newBehavior` is anything with type `UntypedReceive`. A `UntypedReceive` is just a function (or an object, if you like) that +can be returned from another function. We will leverage this feature to track the state of our actor. + +As the first step, instead of defining `OnReceive` directly, we delegate to another function to create the `UntypedReceive`, which +we will call `WaitingForReplies`. This will keep track of two changing values, a `Dictionary` of already received replies +and a `HashSet` of actors that we still wait on. We have three events that we should act on. We can receive a +`RespondTemperature` message from one of the devices. Second, we can receive a `Terminated` message for a device actor +that has been stopped in the meantime. Finally, we can reach the deadline and receive a `CollectionTimeout`. In the +first two cases, we need to keep track of the replies, which we now simply delegate to a method `receivedResponse` which +we will discuss later. In the case of timeout, we need to simply take all the actors that have not yet replied yet +(the members of the set `stillWaiting`) and put a `DeviceTimedOut` as the status in the final reply. Then we +reply to the submitter of the query with the collected results and stop the query actor: + +[!code-csharp[DeviceGroupQuery.cs](../../examples/Tutorials/Tutorial4/DeviceGroupQuery.cs?name=query-state)] + +What is not yet clear, how we will "mutate" the `answersSoFar` and `stillWaiting` data structures. One important +thing to note is that the function `WaitingForReplies` **does not handle the messages directly. It returns a `UntypedReceive` +function that will handle the messages**. This means that if we call `waitingForReplies` again, with different parameters, +then it returns a brand new `UntypedReceive` that will use those new parameters. We have seen how we +can install the initial `UntypedReceive` by simply returning it from `OnReceive`. In order to install a new one, to record a +new reply, for example, we need some mechanism. This mechanism is the method `Context.Become(newReceive)` which will +_change_ the actor's message handling function to the provided `newReceive` function. You can imagine that before +starting, your actor automatically calls `Context.Become(receive)`, i.e. installing the `UntypedReceive` function that +is returned from `OnReceive`. This is another important observation: **it is not `OnReceive` that handles the messages, +it just returns a `UntypedReceive` function that will actually handle the messages**. + +We now have to figure out what to do in `receivedResponse`. First, we need to record the new result in the map +`repliesSoFar` and remove the actor from `stillWaiting`. The next step is to check if there are any remaining actors +we are waiting for. If there is none, we send the result of the query to the original requester and stop +the query actor. Otherwise, we need to update the `repliesSoFar` and `stillWaiting` structures and wait for more +messages. + +In the code before, we treated `Terminated` as the implicit response `DeviceNotAvailable`, so `receivedResponse` does +not need to do anything special. However, there is one small task we still need to do. It is possible that we receive a proper +response from a device actor, but then it stops during the lifetime of the query. We don't want this second event +to overwrite the already received reply. In other words, we don't want to receive `Terminated` after we recorded the +response. This is simple to achieve by calling `Context.Unwatch(ref)`. This method also ensures that we don't +receive `Terminated` events that are already in the mailbox of the actor. It is also safe to call this multiple times, +only the first call will have any effect, the rest is simply ignored. + +With all this knowledge, we can create the `receivedResponse` method: + +[!code-csharp[DeviceGroupQuery.cs](../../examples/Tutorials/Tutorial4/DeviceGroupQuery.cs?name=query-collect-reply)] + +It is quite natural to ask at this point, what have we gained by using the `Context.Become()` trick instead of +just making the `repliesSoFar` and `stillWaiting` structures mutable fields of the actor (i.e. `var`s)? In this +simple example, not that much. The value of this style of state keeping becomes more evident when you suddenly have +_more kinds_ of states. Since each state +might have temporary data that is relevant itself, keeping these as fields would pollute the global state +of the actor, i.e. it is unclear what fields are used in what state. Using parameterized `OnReceive` "factory" +methods we can keep data private that is only relevant to the state. It is still a good exercise to +rewrite the query using mutable fields instead of `Context.Become()`. However, it is recommended to get comfortable +with the solution we have used here as it helps structuring more complex actor code in a cleaner and more maintainable way. + +Our query actor is now done: + +[!code-csharp[DeviceGroupQuery.cs](../../examples/Tutorials/Tutorial4/DeviceGroupQuery.cs?name=query-full)] + +## Testing + +Now let's verify the correctness of the query actor implementation. There are various scenarios we need to test individually to make +sure everything works as expected. To be able to do this, we need to simulate the device actors somehow to exercise +various normal or failure scenarios. Thankfully we took the list of collaborators (actually a `Dictionary`) as a parameter +to the query actor, so we can easily pass in `TestProbe` references. In our first test, we try out the case when +there are two devices and both report a temperature: + +[!code-csharp[DeviceGroupQuerySpec.cs](../../examples/Tutorials/Tutorial4/DeviceGroupQuerySpec.cs?name=query-test-normal)] + +That was the happy case, but we know that sometimes devices cannot provide a temperature measurement. This +scenario is just slightly different from the previous: + +[!code-csharp[DeviceGroupQuerySpec.cs](../../examples/Tutorials/Tutorial4/DeviceGroupQuerySpec.cs?name=query-test-no-reading)] + +We also know, that sometimes device actors stop before answering: + +[!code-csharp[DeviceGroupQuerySpec.cs](../../examples/Tutorials/Tutorial4/DeviceGroupQuerySpec.cs?name=query-test-stopped)] + +If you remember, there is another case related to device actors stopping. It is possible that we get a normal reply +from a device actor, but then receive a `Terminated` for the same actor later. In this case, we would like to keep +the first reply and not mark the device as `DeviceNotAvailable`. We should test this, too: + +[!code-csharp[DeviceGroupQuerySpec.cs](../../examples/Tutorials/Tutorial4/DeviceGroupQuerySpec.cs?name=query-test-stopped-later)] + +The final case is when not all devices respond in time. To keep our test relatively fast, we will construct the +`DeviceGroupQuery` actor with a smaller timeout: + +[!code-csharp[DeviceGroupQuerySpec.cs](../../examples/Tutorials/Tutorial4/DeviceGroupQuerySpec.cs?name=query-test-timeout)] + +Our query works as expected now, it is time to include this new functionality in the `DeviceGroup` actor now. + +## Adding the Query Capability to the Group + +Including the query feature in the group actor is fairly simple now. We did all the heavy lifting in the query actor +itself, the group actor only needs to create it with the right initial parameters and nothing else. + +[!code-csharp[DeviceGroupQueryInProgress.cs](../../examples/Tutorials/Tutorial4/DeviceGroupQueryInProgress.cs?name=query-added)] + +It is probably worth to reiterate what we said at the beginning of the chapter. By keeping the temporary state +that is only relevant to the query itself in a separate actor we keep the group actor implementation very simple. It delegates +everything to child actors and therefore does not have to keep state that is not relevant to its core business. Also, multiple queries can +now run parallel to each other, in fact, as many as needed. In our case querying an individual device actor is a fast operation, but +if this were not the case, for example, because the remote sensors need to be contacted over the network, this design +would significantly improve throughput. + +We close this chapter by testing that everything works together. This test is just a variant of the previous ones, +now exercising the group query feature: + +[!code-csharp[DeviceGroupSpec.cs](../../examples/Tutorials/Tutorial4/DeviceGroupSpec.cs?name=group-query-integration-test)] diff --git a/docs/articles/networking/io.md b/docs/articles/networking/io.md index 18fd388eeb6..64ae6fcb68a 100644 --- a/docs/articles/networking/io.md +++ b/docs/articles/networking/io.md @@ -34,7 +34,7 @@ The following diagram illustrate the actors involved in establishing and handlin The following example shows a simple Telnet client. The client send lines entered in the console to the TCP connection, and write data received from the network to the console. -[!code-csharp[Main](../../examples/Networking/IO/TelnetClient.cs?range=10-63)] +[!code-csharp[Main](../../examples/DocsExamples/Networking/IO/TelnetClient.cs?range=10-63)] #### Server Connection To accept connections, an actor sends an `Tcp.Bind` message to the TCP manager, passing the `bind handler` in the message. @@ -48,6 +48,6 @@ The following diagram illustrate the actor and messages. The following code example shows a simple server that echo's data received from the network. -[!code-csharp[Main](../../examples/Networking/IO/EchoServer.cs?range=8-29)] +[!code-csharp[Main](../../examples/DocsExamples/Networking/IO/EchoServer.cs?range=8-29)] -[!code-csharp[Main](../../examples/Networking/IO/EchoConnection.cs?range=6-27)] +[!code-csharp[Main](../../examples/DocsExamples/Networking/IO/EchoConnection.cs?range=6-27)] diff --git a/docs/articles/networking/serialization.md b/docs/articles/networking/serialization.md index 4d0dcca8dde..f4fa885d3e0 100644 --- a/docs/articles/networking/serialization.md +++ b/docs/articles/networking/serialization.md @@ -13,11 +13,11 @@ actors. In Akka.NET, messages are plain objects and thus easily converted to a byte array. The process of converting objects into byte arrays is known as serialization. -Akka.NET comes with several built-in serializers. However cases will arise that -require the need for other serializing options. The framework provides for -custom serializers to be written. As shown in the examples further down this -page, these serializers can be mixed and matched depending on preference -or need. +Akka.NET itself uses `Protocol Buffers` to serialize internal messages (i.e. +cluster gossip messages). However, the serialization mechanism in Akka.NET allows +you to write custom serializers and to define which serializer to use for what. +As shown in the examples further down this page, these serializers can be mixed +and matched depending on preference or need. There are many other uses for serialization other than messaging. It's possible to use these serializers for ad-hoc purposes as well. @@ -27,7 +27,7 @@ to use these serializers for ad-hoc purposes as well. ### Configuration For Akka.NET to know which `Serializer` to use when (de-)serializing objects, two sections need to be defined in the application's configuration. The -"akka.actor.serializers" section is where names are associated to +`akka.actor.serializers` section is where names are associated to implementations of the `Serializer` to use. ```hocon @@ -35,14 +35,13 @@ akka { actor { serializers { json = "Akka.Serialization.NewtonSoftJsonSerializer" - java = "Akka.Serialization.JavaSerializer" # not used, reserves serializer identifier bytes = "Akka.Serialization.ByteArraySerializer" } } } ``` -The "akka.actor.serialization-bindings" section is where object types are +The `akka.actor.serialization-bindings` section is where object types are associated to a `Serializer` by the names defined in the previous section. ```hocon @@ -50,15 +49,14 @@ akka { actor { serializers { json = "Akka.Serialization.NewtonSoftJsonSerializer" - java = "Akka.Serialization.JavaSerializer" # not used, reserves serializer identifier bytes = "Akka.Serialization.ByteArraySerializer" - myown = "Acme.Inc.MySerializer, MyAssembly" + myown = "MySampleProject.MySerializer, MyAssembly" } serialization-bindings { "System.Byte[]" = bytes "System.Object" = json - "Acme.Inc.MyMessage, MyAssembly" = myown + "MySampleProject.MyOwnSerializable, MyAssembly" = myown } } } @@ -67,15 +65,18 @@ akka { In case of ambiguity, a message implements several of the configured classes, the most specific configured class will be used, i.e. the one of which all other candidates are superclasses. If this condition cannot be met, -because e.g. ISerializable and MyOwnSerializable both apply and neither is a +because e.g. `ISerializable` and `MyOwnSerializable` both apply and neither is a subtype of the other, a warning will be issued. -Akka.NET provides serializers for POCO's (Plain Old C# Objects) by default, so -normally you don't need to add configuration for that. +Akka.NET provides serializers for POCO's (Plain Old C# Objects) and for +`Google.Protobuf.IMessage` by default, so normally you don't need to add +configuration for that. ### Verification -To verify that messages are serializable, the "serialize-message" option can be -enabled. +Normally, messages sent between local actors (i.e. same CLR) do not undergo serialization. +For testing, sometimes, it may be desirable to force serialization on all messages +(both remote and local). If you want to do this in order to verify that your messages +are serializable you can enable the following config option: ```hocon akka { actor { @@ -83,11 +84,7 @@ akka { } } ``` -> [!WARNING] -> We only recommend enabling this config option when running tests. It is completely pointless to have it turned on in other scenarios. - -To verify that an actor's `Props` are serializable, the "serialize-creators" -option can be enabled. +If you want to verify that your `Props` are serializable you can enable the following config option: ```hocon akka { @@ -98,7 +95,7 @@ akka { ``` > [!WARNING] -> We only recommend enabling this config option when running tests. It is completely pointless to have it turned on in other scenarios. +> We recommend having these config options turned on only when you're running tests. Turning these options on in production is pointless, as it would negatively impact the performance of local message passing without giving any gain. ### Programmatic As mentioned previously, Akka.NET uses serialization for message passing. @@ -131,65 +128,16 @@ string back = (string)serializer.FromBinary(bytes, original.GetType()); Assert.AreEqual(original, back); ``` -### Customization +## Customization Akka.NET makes it extremely easy to create custom serializers to handle a wide variety of scenarios. All serializers in Akka.NET inherit from `Akka.Serialization.Serializer`. So to create a custom serializer, all that is needed is a class that inherits from this base class. -### Creating a custom serializer -In the second [example](xref:configuration) on this page, a custom serializer -`Acme.Inc.MySerializer` is configured. That custom serializer can be defined -like the following: - -```csharp -using Akka.Actor; -using Akka.Serialization; -public class MySerializer : Serializer -{ - /// - /// Determines whether the deserializer needs a type hint to deserialize - /// an object. - /// - public override bool IncludeManifest() - { - return false; - } +### Creating new Serializers +A custom `Serializer` has to inherit from `Akka.Serialization.Serializer` and can be defined like the following: - /// - /// Completely unique value to identify this implementation of the - /// used to optimize network traffic - /// - public override int Identifier() - { - return 1234567; // 0 - 16 is reserved by Akka itself - } - - // - // Serializes the given object into a byte array - // - /// The object to serialize - /// A byte array containing the serialized object - public override byte[] ToBinary(object obj) - { - // Put the code that serializes the object here - // ... ... - } - - /// - /// Deserializes a byte array into an object using the type hint - // (if any, see "IncludeManifest" above) - /// - /// The array containing the serialized object - /// The type hint of the object contained in the array - /// The object contained in the array - public override object FromBinary(byte[] bytes, Type type) - { - // Put your code that deserializes here - // ... ... - } -} -``` +[!code-csharp[Main](../../examples/DocsExamples/Networking/Serialization/CreateCustomSerializer.cs?range=7-42)] The only thing left to do for this class would be to fill in the serialization logic in the ``ToBinary(object)`` method and the deserialization logic in the @@ -197,8 +145,22 @@ logic in the ``ToBinary(object)`` method and the deserialization logic in the updated to reflect which name to bind to and the classes that use this serializer. -### Serializing Actors -All actors are serializable using the default serializer, but in cases were +### Serializer with String Manifest +The `Serializer` illustrated above supports a class based manifest (type hint). For serialization of data that need to evolve over time the `SerializerWithStringManifest` is recommended instead of `Serializer` because the manifest (type hint) is a `String` instead of a `Type`. That means that the class can be moved/removed and the serializer can still deserialize old data by matching on the String. This is especially useful for `Persistence`. + +The manifest string can also encode a version number that can be used in `FromBinary` to deserialize in different ways to migrate old data to new domain objects. + +If the data was originally serialized with `Serializer` and in a later version of the system you change to `SerializerWithStringManifest` the manifest string will be the full class name if you used `IncludeManifest=true`, otherwise it will be the empty string. + +This is how a `SerializerWithStringManifest` looks like: +[!code-csharp[Main](../../examples/DocsExamples/Networking/Serialization/MyOwnSerializer2.cs?range=9-66)] + +You must also bind it to a name in your `Configuration` and then list which classes that should be serialized using it. + +It's recommended to throw `SerializationException` in `FromBinary` if the manifest is unknown. This makes it possible to introduce new message types and send them to nodes that don't know about them. This is typically needed when performing rolling upgrades, i.e. running a cluster with mixed versions for while. `SerializationException` is treated as a transient problem in the TCP based remoting layer. The problem will be logged and message is dropped. Other exceptions will tear down the TCP connection because it can be an indication of corrupt bytes from the underlying transport. + +### Serializing ActorRefs +All actors are serializable using the default protobuf serializer, but in cases were custom serializers are used, we need to know how to (de-)serialize them properly. In the general case, the local address to be used depends on the type of remote address which shall be the recipient of the serialized @@ -229,58 +191,16 @@ logical context, but it is not enough when deserializing it on a different network host: for that it would need to include the system's remote transport address. An actor system is not limited to having just one remote transport per se, which makes this question a bit more interesting. To find out the -appropriate address to use when sending to remoteAddr you can use +appropriate address to use when sending to `remoteAddr` you can use `IActorRefProvider.GetExternalAddressFor(remoteAddr)` like this: -.. includecode:: code/docs/serialization/ExternalAddress.cs - - +.[!code-csharp[Main](../../examples/DocsExamples/Networking/Serialization/ExternalAddressProvider.cs?range=7-66)] > [!NOTE] -> `ActorPath.ToSerializationFormatWithAddress` differs from `ToString` if the address does not already have host and port components, i.e. it only inserts address information for local addresses. - -`ToSerializationFormatWithAddress` also adds the unique id of the actor, which +> `ActorPath.ToSerializationFormatWithAddress` differs from `ToString` if the address +does not already have `host` and `port` components, i.e. it only inserts address +information for local addresses. +> `ToSerializationFormatWithAddress` also adds the unique id of the actor, which will change when the actor is stopped and then created again with the same name. Sending messages to a reference pointing the old actor will not be delivered to the new actor. If you do not want this behavior, e.g. in case of long term @@ -290,46 +210,16 @@ include the unique id. This requires that you know at least which type of address will be supported by the system which will deserialize the resulting actor reference; if you have no concrete address handy you can create a dummy one for the right protocol using -new Address(protocol, "", "", 0) (assuming that the actual transport used is as -lenient as Akka's RemoteActorRefProvider). - -There is also a default remote address which is the one used by cluster support -(and typical systems have just this one); you can get it like this: - -.. includecode:: code/docs/serialization/DefaultAddress.cs - - +### Deep serialization of Actors +The recommended approach to do deep serialization of internal actor state is +to use [Akka Persistence](xref:persistence-architecture). -### How to setup Hyperion as default serializer +## How to setup Hyperion as default serializer -Starting from Akka.NET v1.5, default Newtonsoft.Json serializer will be replaced in the favor of [Hyperion](https://github.com/akkadotnet/Hyperion). At the present moment, wire is required by some of the newer plugins (like `Akka.Cluster.Tools`). This change may break compatibility with older actors still using json serializer for remoting or persistence. If it's possible, it's advised to migrate to it already. To do so, first you need to reference hyperion serializer as NuGet package inside your project: +Starting from Akka.NET v1.5, default Newtonsoft.Json serializer will be replaced in the favor of [Hyperion](https://github.com/akkadotnet/Hyperion). This change may break compatibility with older actors still using json serializer for remoting or persistence. If it's possible, it's advised to migrate to it already. To do so, first you need to reference hyperion serializer as NuGet package inside your project: Install-Package Akka.Serialization.Hyperion -pre @@ -347,7 +237,3 @@ akka { } } ``` - -### Deep serialization of Actors -The recommended approach to do deep serialization of internal actor state is -to use [Akka Persistence](xref:Persistence). diff --git a/docs/articles/persistence/at-least-once-delivery.md b/docs/articles/persistence/at-least-once-delivery.md index 8b6888cc383..87d1831c9d9 100644 --- a/docs/articles/persistence/at-least-once-delivery.md +++ b/docs/articles/persistence/at-least-once-delivery.md @@ -26,9 +26,9 @@ If the persistent actor is not currently recovering, the deliver method will sen Deliver requires a `deliveryMessageMapper` function to pass the provided `deliveryId` into the message so that the correlation between `Deliver` and `ConfirmDelivery` is possible. The `deliveryId` must do the round trip. Upon receipt of the message, the destination actor will send the same `deliveryId` wrapped in a confirmation message back to the sender. The sender will then use it to call the `ConfirmDelivery` method to complete the delivery routine. -[!code-csharp[Main](../../examples/Persistence/AtLeastOnceDelivery/AtLeastOnceDeliveryActor.Messages.cs?range=3-49)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/AtLeastOnceDelivery/AtLeastOnceDeliveryActor.Messages.cs?range=3-49)] -[!code-csharp[Main](../../examples/Persistence/AtLeastOnceDelivery/ExampleAtLeastOnceDeliveryReceiveActor.cs?range=6-48)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/AtLeastOnceDelivery/ExampleAtLeastOnceDeliveryReceiveActor.cs?range=6-48)] The `deliveryId` generated by the persistence module is a strictly monotonically increasing sequence number without gaps. The same sequence is used for all destinations of the actor, i.e. when sending to multiple destinations the destinations will see gaps in the sequence. It is not possible to use custom `deliveryId`. However, you can send a custom correlation identifier in the message to the destination. You must then retain a mapping between the internal `deliveryId` (passed into the `deliveryMessageMapper` function) and your custom correlation id (passed into the message). You can do this by storing such mapping in a Map(CorrelationId -> DeliveryId) from which you can retrieve the `deliveryId` to be passed into the `ConfirmDelivery` method once the receiver of your message has replied with your custom correlation id. diff --git a/docs/articles/persistence/event-sourcing.md b/docs/articles/persistence/event-sourcing.md index cfdb4c6b641..4737234aa32 100644 --- a/docs/articles/persistence/event-sourcing.md +++ b/docs/articles/persistence/event-sourcing.md @@ -8,7 +8,7 @@ The basic idea behind Event Sourcing is quite simple. A persistent actor receive Akka persistence supports event sourcing with the `UntypedPersistentActor` abstract class. An actor that extends this class uses the persist method to persist and handle events. The behavior of an `UntypedPersistentActor` is defined by implementing `OnRecover` and `OnCommand` methods. This is demonstrated in the following example. -[!code-csharp[Main](../../examples/Persistence/PersistentActor/PersistentActor.cs?range=9-101)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/PersistentActor/PersistentActor.cs?range=9-101)] The example defines two data types, `Cmd` and `Evt` to represent commands and events, respectively. The state of the `PersistentActor` is a list of persisted event data contained in `ExampleState`. The persistent actor's `OnRecover` method defines how state is updated during recovery by handling `Evt` and `SnapshotOffer` messages. The persistent actor's `OnCommand` method is a command handler. In this example, a command is handled by generating two events which are then persisted and handled. Events are persisted by calling `Persist` with an event (or a sequence of events) as first argument and an event handler as second argument. @@ -35,7 +35,11 @@ public override string PersistenceId { get; } = "my-stable-persistence-id"; > `PersistenceId` must be unique to a given entity in the journal (database table/keyspace). When replaying messages persisted to the journal, you query messages with a `PersistenceId`. So, if two different entities share the same `PersistenceId`, message-replaying behavior is corrupted. ## Recovery -By default, a persistent actor is automatically recovered on start and on restart by replaying journaled messages. New messages sent to a persistent actor during recovery do not interfere with replayed messages. They are cached and received by a persistent actor after recovery phase completes. +By default, a persistent actor is automatically recovered on start and on restart by replaying journaled messages. New messages sent to a persistent actor during recovery do not interfere with replayed messages. They are stashed and received by a persistent actor after recovery phase completes. + +The number of concurrent recoveries of recoveries that can be in progress at the same time is limited to not overload the system and the backend data store. When exceeding the limit the actors will wait until other recoveries have been completed. This is configured by: + + akka.persistence.max-concurrent-recoveries = 50 > [!NOTE] > Accessing the `Sender` for replayed messages will always result in a `DeadLetters` reference, as the original sender is presumed to be long gone. If you indeed have to notify an actor during recovery in the future, store its `ActorPath` explicitly in your persisted events. @@ -129,7 +133,7 @@ In the below example, the event callbacks may be called "at any time", even afte > [!NOTE] > In order to implement the pattern known as "command sourcing" simply `PersistAsync` all incoming messages right away and handle them in the callback. -[!code-csharp[Main](../../examples/Persistence/PersistentActor/PersistAsync.cs?range=8-45)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/PersistentActor/PersistAsync.cs?range=8-45)] > [!WARNING] > The callback will not be invoked if the actor is restarted (or stopped) in between the call to `PersistAsync` and the journal has confirmed the write. @@ -139,7 +143,7 @@ Sometimes when working with `PersistAsync` or `Persist` you may find that it wou Using this method is very similar to the persist family of methods, yet it does **not** persist the passed in event. It will be kept in memory and used when invoking the handler. -[!code-csharp[Main](../../examples/Persistence/PersistentActor/Defer.cs?range=8-27)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/PersistentActor/Defer.cs?range=8-27)] Notice that the `Sender` is safe to access in the handler callback, and will be pointing to the original sender of the command for which this `DeferAsync` handler was called. @@ -161,7 +165,7 @@ persistentActor.tell("b"); ``` You can also call `DeferAsync` with `Persist`. -[!code-csharp[Main](../../examples/Persistence/PersistentActor/DeferWithPersist.cs?range=8-27)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/PersistentActor/DeferWithPersist.cs?range=8-27)] > [!WARNING] > The callback will not be invoked if the actor is restarted (or stopped) in between the call to `DeferAsync` and the journal has processed and confirmed all preceding writes.. @@ -172,21 +176,21 @@ It is possible to call `Persist` and `PersistAsync` inside their respective call In general it is encouraged to create command handlers which do not need to resort to nested event persisting, however there are situations where it may be useful. It is important to understand the ordering of callback execution in those situations, as well as their implication on the stashing behaviour (that persist enforces). In the following example two persist calls are issued, and each of them issues another persist inside its callback: -[!code-csharp[Main](../../examples/Persistence/PersistentActor/NestedPersists.cs?range=8-36)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/PersistentActor/NestedPersists.cs?range=8-36)] When sending two commands to this `UntypedPersistentActor`, the persist handlers will be executed in the following order: -[!code-csharp[Main](../../examples/Persistence/PersistentActor/NestedPersists.cs?range=43-57)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/PersistentActor/NestedPersists.cs?range=43-57)] First the "outer layer" of persist calls is issued and their callbacks are applied. After these have successfully completed, the inner callbacks will be invoked (once the events they are persisting have been confirmed to be persisted by the journal). Only after all these handlers have been successfully invoked will the next command be delivered to the persistent Actor. In other words, the stashing of incoming commands that is guaranteed by initially calling `Persist` on the outer layer is extended until all nested persist callbacks have been handled. It is also possible to nest `PersistAsync` calls, using the same pattern: -[!code-csharp[Main](../../examples/Persistence/PersistentActor/NestedPersistsAsync.cs?range=8-36)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/PersistentActor/NestedPersistsAsync.cs?range=8-36)] In this case no stashing is happening, yet events are still persisted and callbacks are executed in the expected order: -[!code-csharp[Main](../../examples/Persistence/PersistentActor/NestedPersistsAsync.cs?range=43-60)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/PersistentActor/NestedPersistsAsync.cs?range=43-60)] While it is possible to nest mixed `Persist` and `PersistAsync` with keeping their respective semantics it is not a recommended practice, as it may lead to overly complex nesting. @@ -267,9 +271,9 @@ This can be dangerous when used with `UntypedPersistentActor` due to the fact th The example below highlights how messages arrive in the Actor's mailbox and how they interact with its internal stashing mechanism when `Persist()` is used. Notice the early stop behaviour that occurs when `PoisonPill` is used: -[!code-csharp[Main](../../examples/Persistence/PersistentActor/AvoidPoisonPill.cs?range=9-35)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/PersistentActor/AvoidPoisonPill.cs?range=9-35)] -[!code-csharp[Main](../../examples/Persistence/PersistentActor/AvoidPoisonPill.cs?range=42-68)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/PersistentActor/AvoidPoisonPill.cs?range=42-68)] ## Replay filter There could be cases where event streams are corrupted and multiple writers (i.e. multiple persistent actor instances) journaled different messages with the same sequence number. In such a case, you can configure how you filter replayed messages from multiple writers, upon recovery. diff --git a/docs/articles/persistence/persistent-fsm.md b/docs/articles/persistence/persistent-fsm.md index 7d2175fe983..128255668e7 100644 --- a/docs/articles/persistence/persistent-fsm.md +++ b/docs/articles/persistence/persistent-fsm.md @@ -6,36 +6,73 @@ title: Persistence FSM `PersistentFSM` handles the incoming messages in an FSM like fashion. Its internal state is persisted as a sequence of changes, later referred to as domain events. Relationship between incoming messages, FSM's states and transitions, persistence of domain events is defined by a DSL. -> [!WARNING] -> PersistentFSM is marked as `experimental`. - +## A Simple Example To demonstrate the features of the `PersistentFSM` class, consider an actor which represents a Web store customer. The contract of our "`WebStoreCustomerFSMActor`" is that it accepts the following commands: -[!code-csharp[Main](../../examples/Persistence/PersistentFSM/PersistentFSM.Commands.cs?range=3-27)] +[!code-csharp[WebStoreCustomerFSMActor.cs](../../examples/DocsExamples/Persistence/WebStoreCustomerFSMActor.cs?name=persistent-fsm-commands)] `AddItem` sent when the customer adds an item to a shopping cart `Buy` - when the customer finishes the purchase `Leave` - when the customer leaves the store without purchasing anything `GetCurrentCart` allows to query the current state of customer's shopping cart The customer can be in one of the following states: -[!code-csharp[Main](../../examples/Persistence/PersistentFSM/PersistentFSM.State.cs?range=3-9)] +[!code-csharp[WebStoreCustomerFSMActor.cs](../../examples/DocsExamples/Persistence/WebStoreCustomerFSMActor.cs?name=persistent-fsm-states)] `LookingAround` customer is browsing the site, but hasn't added anything to the shopping cart `Shopping` customer has recently added items to the shopping cart `Inactive` customer has items in the shopping cart, but hasn't added anything recently `Paid` customer has purchased the items +> [!NOTE] +> `PersistentFSM` states must inherit from trait `PersistentFSM.IFsmState` and implement the `string Identifier` property. This is required in order to simplify the serialization of FSM states. String identifiers should be unique! + Customer's actions are "recorded" as a sequence of "domain events" which are persisted. Those events are replayed on an actor's start in order to restore the latest customer's state: -[!code-csharp[Main](../../examples/Persistence/PersistentFSM/PersistentFSM.Events.cs?range=3-23)] +[!code-csharp[WebStoreCustomerFSMActor.cs](../../examples/DocsExamples/Persistence/WebStoreCustomerFSMActor.cs?name=persistent-fsm-domain-events)] Customer state data represents the items in a customer's shopping cart: -[!code-csharp[Main](../../examples/Persistence/PersistentFSM/PersistentFSM.Messages.cs?range=5-65)] +[!code-csharp[WebStoreCustomerFSMActor.cs](../../examples/DocsExamples/Persistence/WebStoreCustomerFSMActor.cs?name=persistent-fsm-domain-messages)] Side-effects: -[!code-csharp[Main](../../examples/Persistence/PersistentFSM/PersistentFSM.SideEffects.cs?range=3-13)] +[!code-csharp[WebStoreCustomerFSMActor.cs](../../examples/DocsExamples/Persistence/WebStoreCustomerFSMActor.cs?name=persistent-fsm-side-effects)] Here is how everything is wired together: -[!code-csharp[Main](../../examples/Persistence/PersistentFSM/ExamplePersistentFSM.cs?range=16-109)] +[!code-csharp[WebStoreCustomerFSMActor.cs](../../examples/DocsExamples/Persistence/WebStoreCustomerFSMActor.cs?name=persistent-fsm-setup)] > [!NOTE] > State data can only be modified directly on initialization. Later it's modified only as a result of applying domain events. Override the `ApplyEvent` method to define how state data is affected by domain events, see the example below -[!code-csharp[Main](../../examples/Persistence/PersistentFSM/ExamplePersistentFSM.cs?range=112-125)] +[!code-csharp[WebStoreCustomerFSMActor.cs](../../examples/DocsExamples/Persistence/WebStoreCustomerFSMActor.cs?name=persistent-fsm-apply-event)] + +`AndThen` can be used to define actions which will be executed following event’s persistence - convenient for "side effects" like sending a message or logging. Notice that actions defined in andThen block are not executed on recovery: +```C# +GoTo(Paid.Instance).Applying(OrderExecuted.Instance).AndThen(cart => +{ + if (cart is NonEmptyShoppingCart nonShoppingCart) + { + reportActor.Tell(new PurchaseWasMade(nonShoppingCart.Items)); + } +}); +``` +A snapshot of state data can be persisted by calling the `SaveStateSnapshot()` method: +```C# +Stop().Applying(OrderDiscarded.Instance).AndThen(cart => +{ + reportActor.Tell(ShoppingCardDiscarded.Instance); + SaveStateSnapshot(); +}); +``` +On recovery state data is initialized according to the latest available snapshot, then the remaining domain events are replayed, triggering the `ApplyEvent` method. + +## Periodical snapshot by snapshot-after + +You can enable periodical `SaveStateSnapshot()` calls in `PersistentFSM` if you turn the following flag on in `reference.conf` +``` +akka.persistence.fsm.snapshot-after = 1000 +``` +this means `SaveStateSnapshot()` is called after the sequence number reaches multiple of 1000. + +> [!NOTE] +> `SaveStateSnapshot()` might not be called exactly at sequence numbers being multiple of the `snapshot-after` configuration value. +This is because `PersistentFSM` works in a sort of "batch" mode when processing and persisting events, and `SaveStateSnapshot()` +is called only at the end of the "batch". For example, if you set `akka.persistence.fsm.snapshot-after = 1000`, +it is possible that `SaveStateSnapshot()` is called at `lastSequenceNr = 1005, 2003, ... ` +A single batch might persist state transition, also there could be multiple domain events to be persisted +if you pass them to `Applying` method in the `PersistentFSM` DSL. diff --git a/docs/articles/persistence/snapshots.md b/docs/articles/persistence/snapshots.md index 7cf7432fbb5..62f9adc4668 100644 --- a/docs/articles/persistence/snapshots.md +++ b/docs/articles/persistence/snapshots.md @@ -8,7 +8,7 @@ Snapshots can dramatically reduce recovery times of persistent actors and views. Persistent actors can save snapshots of internal state by calling the `SaveSnapshot` method. If saving of a snapshot succeeds, the persistent actor receives a `SaveSnapshotSuccess` message, otherwise a `SaveSnapshotFailure` message. -[!code-csharp[Main](../../examples/Persistence/PersistentActor/Snapshots.cs?range=7-45)] +[!code-csharp[Main](../../examples/DocsExamples/Persistence/PersistentActor/Snapshots.cs?range=7-45)] During recovery, the persistent actor is offered a previously saved snapshot via a `SnapshotOffer` message from which it can initialize internal state. diff --git a/docs/articles/remoting/deployment.md b/docs/articles/remoting/deployment.md index 583cb2243c4..0fc1289eca2 100644 --- a/docs/articles/remoting/deployment.md +++ b/docs/articles/remoting/deployment.md @@ -1,5 +1,5 @@ --- -layout: docs.hbs +uid: remote-deployment title: Remote Deployment --- @@ -58,7 +58,7 @@ class Program akka { actor.provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote"" remote { - helios.tcp { + dot-netty.tcp { port = 8090 hostname = localhost } @@ -115,7 +115,7 @@ class Program using (var system = ActorSystem.Create("Deployer", ConfigurationFactory.ParseString(@" akka { actor{ - provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote"" + provider = remote deployment { /remoteecho { remote = ""akka.tcp://DeployTarget@localhost:8090"" @@ -123,7 +123,7 @@ class Program } } remote { - helios.tcp { + dot-netty.tcp { port = 0 hostname = localhost } diff --git a/docs/articles/remoting/index.md b/docs/articles/remoting/index.md index a1af31566db..375414cbdaa 100644 --- a/docs/articles/remoting/index.md +++ b/docs/articles/remoting/index.md @@ -11,16 +11,16 @@ Akka.NET uses the "Home Depot" extensibility model - the base [Akka NuGet packag ## Akka.Remote's Capabilities Akka.Remote introduces the following capabilities to Akka.NET applications: -1. **Location transparency with RemoteActorRef** - write code that looks like it's communicating with local actors, but with just a few configuration settings your actors can begin communicating with actors hosted in remote processes in a way that's fully [location transparent](/concepts/location-transparency.md) to your code. +1. **Location transparency with RemoteActorRef** - write code that looks like it's communicating with local actors, but with just a few configuration settings your actors can begin communicating with actors hosted in remote processes in a way that's fully [location transparent](xref:location-transparency) to your code. 1. **Remote addressing** - Akka.Remote extends the `Address` and `ActorPath` components of Akka.NET to also now include information about how to connect to remote processes via `ActorSelection`. 1. **Remote messaging** - send messages, *transparently*, to actors running in remote `ActorSystem`s elsewhere on the network. 1. **Remote deployment** - remotely deploy actors via the `ActorOf` method onto remote `ActorSystem` instances, anywhere on the network! The location of your actors on the network becomes a deployment detail in Akka.Remote. 1. **Multiple network transports** - out of the box Akka.Remote ships with support for TCP, but has the ability to plugin third party transports and active multiple of them at the same time. -##Distributed by Default -Everything in Akka is designed to work in a distributed setting: all interactions of actors use purely message passing and everything is asynchronous. This effort has been undertaken to ensure that all functions are available equally when running within a single machine or on a cluster of hundreds of machines. The key for enabling this is to go from remote to local by way of optimization instead of trying to go from local to remote by way of generalization. See [this classic paper](http://doc.akka.io/docs/misc/smli_tr-94-29.pdf) for a detailed discussion on why the second approach is bound to fail. +## Distributed by Default +Everything in Akka.NET is designed to work in a distributed setting: all interactions of actors use purely message passing and everything is asynchronous. This effort has been undertaken to ensure that all functions are available equally when running within a single machine or on a cluster of hundreds of machines. The key for enabling this is to go from remote to local by way of optimization instead of trying to go from local to remote by way of generalization. See [this classic paper](http://doc.akka.io/docs/misc/smli_tr-94-29.pdf) for a detailed discussion on why the second approach is bound to fail. -##Ways in which Transparency is Broken +## Ways in which Transparency is Broken What is true of Akka need not be true of the application which uses it, since designing for distributed execution poses some restrictions on what is possible. The most obvious one is that all messages sent over the wire must be serializable. While being a little less obvious this includes closures which are used as actor factories (i.e. within Props) if the actor is to be created on a remote node. Another consequence is that everything needs to be aware of all interactions being fully asynchronous, which in a computer network might mean that it may take several minutes for a message to reach its recipient (depending on configuration). It also means that the probability for a message to be lost is much higher than within one CLR, where it is close to zero (still: no hard guarantee!). @@ -29,7 +29,7 @@ Message size can also be a concern. While in-process messages are only bound by ```hocon akka { - helios.tcp { + dot-netty.tcp { # Maximum frame size: 4 MB maximum-frame-size = 4000000b } @@ -40,17 +40,17 @@ Messages exceeding the maximum size will be dropped. You also have to be aware that some protocols (e.g. UDP) might not support arbitrarily large messages. -##How is Remoting Used? -We took the idea of transparency to the limit in that there is nearly no API for the remoting layer of Akka: it is purely driven by configuration. Just write your application according to the principles outlined in the previous sections, then specify remote deployment of actor sub-trees in the configuration file. This way, your application can be scaled out without having to touch the code. The only piece of the API which allows programmatic influence on remote deployment is that Props contain a field which may be set to a specific Deploy instance; this has the same effect as putting an equivalent deployment into the configuration file (if both are given, configuration file wins). +## How is Remoting Used? +We took the idea of transparency to the limit in that there is nearly no API for the remoting layer of Akka.NET: it is purely driven by configuration. Just write your application according to the principles outlined in the previous sections, then specify remote deployment of actor sub-trees in the configuration file. This way, your application can be scaled out without having to touch the code. The only piece of the API which allows programmatic influence on remote deployment is that Props contain a field which may be set to a specific Deploy instance; this has the same effect as putting an equivalent deployment into the configuration file (if both are given, configuration file wins). -##Peer-to-Peer vs. Client-Server +## Peer-to-Peer vs. Client-Server Akka Remoting is a communication module for connecting actor systems in a peer-to-peer fashion, and it is the foundation for Akka Clustering. The design of remoting is driven by two (related) design decisions: 1. Communication between involved systems is symmetric: if a system A can connect to a system B then system B must also be able to connect to system A independently. 2. The role of the communicating systems are symmetric in regards to connection patterns: there is no system that only accepts connections, and there is no system that only initiates connections. The consequence of these decisions is that it is not possible to safely create pure client-server setups with predefined roles (violates assumption 2) and using setups involving Network Address Translation or Load Balancers (violates assumption 1). -For client-server setups it is better to use HTTP or [Akka I/O](../IO). +For client-server setups it is better to use HTTP or [Akka I/O](xref:akka-io). ### Use Cases Akka.Remote is most commonly used in distributed applications that run across the network, some examples include: @@ -65,7 +65,7 @@ Akka.Remote is most commonly used in distributed applications that run across th That being said, it's a good idea to understand how Akka.Remote works if you intend to use clustering. So keep reading! -##Marking Points for Scaling Up with Routers +## Marking Points for Scaling Up with Routers In addition to being able to run different parts of an actor system on different nodes of a cluster, it is also possible to scale up onto more cores by multiplying actor sub-trees which support parallelization (think for example a search engine processing different queries in parallel). The clones can then be routed to in different fashions, e.g. round-robin. The only thing necessary to achieve this is that the developer needs to declare a certain actor as `WithRouter`, then—in its stead—a router actor will be created which will spawn up a configurable number of children of the desired type and route to them in the configured fashion. Once such a router has been declared, its configuration can be freely overridden from the configuration file, including mixing it with the remote deployment of (some of) the children. Read more about this in [Routers](xref:routers). ## Enabling Akka.Remote @@ -82,11 +82,11 @@ Next, you'll need to enable the `RemoteActorRefProvider` inside [HOCON configura ```xml akka { actor { - provider = "Akka.Remote.RemoteActorRefProvider, Akka.Remote" + provider = remote } remote { - helios.tcp { + dot-netty.tcp { port = 8080 hostname = localhost } @@ -97,33 +97,30 @@ akka { See [Akka Remote Reference Config File](https://github.com/akkadotnet/akka.net/blob/dev/src/core/Akka.Remote/Configuration/Remote.conf) for additional information on HOCON settings available in akka remote. ## Addresses, Transports, Endpoints, and Associations -In the above section we mentioned that you have to bind a *transport* to an IP address and port, we did in that in HOCON inside the `helios.tcp` section. Why did we have to do any of that? +In the above section we mentioned that you have to bind a *transport* to an IP address and port, we did in that in HOCON inside the `dot-netty.tcp` section. Why did we have to do any of that? Well, let's take a step back to define some key terms you'll need to be familiar with in order to use Akka.Remote: -- **Transport** - a "transport" refers to an actual network transport, such as TCP or UDP. By default Akka.Remote uses a [Helios](http://helios-io.github.io/ "Helios - Reactive socket middleware for .NET") TCP transport, but you could write your own transport and use that instead of you wish. +- **Transport** - a "transport" refers to an actual network transport, such as TCP or UDP. By default Akka.Remote uses a [DotNetty](https://github.com/Azure/DotNetty) TCP transport, but you could write your own transport and use that instead of you wish. - **Address** - this refers to an IP address and port combination, just like any other IP-enabled protocol. You can also use a hostname instead of an IP address, but the hostname must be resolved to an IP address first. - **Endpoint** - an "endpoint" is a specific address binding for a transport. If I open a TCP transport at `localhost:8080` then I've created an *endpoint* for that transport at that address. - **Association** - an "association" is a connection between two endpoints, each belonging to a different `ActorSystem`. Must have a valid *outbound* endpoint and a valid *inbound* endpoint in order to create the association. -> [!NOTE] -> Learn more about [Helios and the default Akka.Remote transports](transports.md) here. - These terms form the basis for all remote interaction between `ActorSystem` instances, so they're critically important to learn and distinguish. -So in the case of our previous example, `localhost:8080` is the inbound (listening) endpoint for the Helios TCP transport of the `ActorSystem` we configured. +So in the case of our previous example, `localhost:8080` is the inbound (listening) endpoint for the `DotNetty` TCP transport of the `ActorSystem` we configured. ## How to Form Associations between Remote Systems -So imagine we have the following two actor systems configured to both use the `helios.tcp` Akka.Remote transport: +So imagine we have the following two actor systems configured to both use the `dot-netty.tcp` Akka.Remote transport: **Client** ```xml akka { actor { - provider = "Akka.Remote.RemoteActorRefProvider, Akka.Remote" + provider = remote } remote { - helios.tcp { + dot-netty.tcp { port = 0 # bound to a dynamic port assigned by the OS hostname = localhost } @@ -135,10 +132,10 @@ akka { ```xml akka { actor { - provider = "Akka.Remote.RemoteActorRefProvider, Akka.Remote" + provider = remote } remote { - helios.tcp { + dot-netty.tcp { port = 8081 #bound to a specific port hostname = localhost } @@ -176,11 +173,11 @@ Each `ActorPath` consists of four parts: When you want to connect to a remote `ActorSystem`, two important changes occur to the address: -1. **The protocol gets augmented with the protocol of the network transport** - so in this case, since we're using the Helios TCP transport the protocol for communicating with all remote actors in our `ActorSystem` changes from `akka://` to `akka.tcp://`. When you deploy an actor remotely or send a message to a remote actor via `ActorSelection`, specifying this protocol is what tells your local `ActorSystem` how to deliver this message to the remote one! +1. **The protocol gets augmented with the protocol of the network transport** - so in this case, since we're using the DotNetty TCP transport the protocol for communicating with all remote actors in our `ActorSystem` changes from `akka://` to `akka.tcp://`. When you deploy an actor remotely or send a message to a remote actor via `ActorSelection`, specifying this protocol is what tells your local `ActorSystem` how to deliver this message to the remote one! 2. **The address gets populated with the inbound endpoint on the transport** - `localhost:9001` in this case. This lets your local system know how to attempt to establish an *outbound endpoint* to the remote `ActorSystem`. > [!NOTE] -> for more information about addressing in Akka.NET, see [Actor References, Paths and Addresses](/concepts/addressing.md) +> For more information about addressing in Akka.NET, see [Actor References, Paths and Addresses](xref:addressing) Here's how we actually use a remote `Address` to form an association between two remote `ActorSystem` instances. diff --git a/docs/articles/remoting/messaging.md b/docs/articles/remoting/messaging.md index b50509d03c2..53ee37da865 100644 --- a/docs/articles/remoting/messaging.md +++ b/docs/articles/remoting/messaging.md @@ -7,7 +7,7 @@ title: Remote Messaging Once you [form an association between two `ActorSystem`s](index.md#how-to-form-associations-between-remote-systems), you can now send messages transparently between actors regardless of where they are on the network. ## Serialization -[Serialization of messages in Akka.NET is transparent](../Serialization), but in order to achieve that transparency there are some practices you need to observe in how you design your project. +[Serialization of messages in Akka.NET is transparent](xref:serialization), but in order to achieve that transparency there are some practices you need to observe in how you design your project. * **Akka.NET serialization is strongly typed** - if you serialize a message of type `Foo.FooMessage.MyMessage, Foo.dll` (this is a [Fully Qualified Type Name (FQN)](https://msdn.microsoft.com/en-us/library/yfsftwz6.aspx)) then Akka.NET will look for *that exact type* when it attempts to deserialize your message. If that type isn't found, deserialization fails. * **Therefore, all of your network messages should be defined in shared assemblies** that are referenced by all of the applications running Akka.NET `ActorSystem`s who will be communicating remotely. @@ -16,7 +16,7 @@ Once you [form an association between two `ActorSystem`s](index.md#how-to-form-a When your `ActorSystem` boots, it won't have any associations to other remote systems - so you have to establish one by sending a message to a remote actor via `ActorSelection` initially which you can do by sending a message to an [actor's remote `ActorPath`](index.md#addressing-a-remote-actorsystem). > [!NOTE] -> You can also establish an association by [deploying actors onto a remote `ActorSystem`](deployment.md). +> You can also establish an association by [deploying actors onto a remote `ActorSystem`](xref:remote-deployment). Let's consider the following two actors and some message classes. @@ -71,6 +71,7 @@ In essence, minus the initial `ActorSelection` used to start remote communicatio ## `RemoteActorRef` and Location Transparency What `RemoteActorRef` gives us is a magical property called [Location Transparency](/concepts/location-transparency.md). +> [!NOTE] > What location transparency means is that whenever you send a message to an actor, you don't need to know where they are within an actor system, which might span hundreds of computers. You just have to know that actors' address. It's the job of the `RemoteActorRef` to make a remote actor running on in a different process look and feel exactly the same as an `IActorRef` running locally inside the same process as your code. This is what it means to "have a transparent location." diff --git a/docs/articles/remoting/security.md b/docs/articles/remoting/security.md index 8fe4a83a668..a185ae92ff5 100644 --- a/docs/articles/remoting/security.md +++ b/docs/articles/remoting/security.md @@ -4,13 +4,47 @@ title: Network Security --- # Akka.Remote Security -This section is extremely brief - as of today there are no built-in secure transports in Akka.Remote. Security is a "do it yourself" exercise. -That being said, however, [Helios - the socket library that powers all of the transports in Akka.Remote](http://helios-io.github.io/ "Helios - Reactive socket middleware for .NET"), is working on plans to introduce [TLS](http://en.wikipedia.org/wiki/Transport_Layer_Security) and [DTLS](http://en.wikipedia.org/wiki/Datagram_Transport_Layer_Security) inside Helios 2.0, which will bring asymmetric encryption and secure sockets to Akka.Remote. +There are 2 ways you may like to achieve network security when using Akka.Remote: -But in the meantime, we have to create our own security options around Akka.Remote. +- Transport Layer Security (introduced with Akka.Remote Version 1.2) +- Virtual Private Networks -### Secure the Network: Akka.Remote with Virtual Private Networks +### Akka.Remote with TLS (Transport Layer Security) +The release of Akka.NET version 1.2.0 introduces the default [DotNetty](https://github.com/Azure/DotNetty) transport and the ability to configure [TLS](http://en.wikipedia.org/wiki/Transport_Layer_Security) security across Akka.Remote Actor Systems. In order to use TLS, you must first install a valid SSL certificate on all Akka.Remote hosts that you intend to use TLS. + +Once you've installed valid SSL certificates, TLS is enabled via your HOCON configuration by setting `enable-ssl = true` and configuring the `ssl` HOCON configuration section like below: + +``` +akka { + loglevel = DEBUG + actor { + provider = Akka.Remote.RemoteActorRefProvider,Akka.Remote + } + remote { + dot-netty.tcp { + port = 0 + hostname = 127.0.0.1 + enable-ssl = true + log-transport = true + ssl { + suppress-validation = true + certificate { + # valid ssl certificate must be installed on both hosts + path = "" + password = "" + # flags is optional: defaults to "default-flag-set" key storage flag + # other available storage flags: + # exportable | machine-key-set | persist-key-set | user-key-set | user-protected + flags = [ "default-flag-set" ] + } + } + } + } +} +``` + +### Akka.Remote with Virtual Private Networks The absolute best practice for securing remote Akka.NET applications today is to make the network around the applications secure - don't use public, open networks! Instead, use a private network to restrict machines that can contact Akka.Remote processes to ones who have your VPN credentials. Some options for doing this: diff --git a/docs/articles/remoting/transports.md b/docs/articles/remoting/transports.md index d1857ccc1f6..68ed8d9cf89 100644 --- a/docs/articles/remoting/transports.md +++ b/docs/articles/remoting/transports.md @@ -1,12 +1,12 @@ --- -layout: docs.hbs +uid: remote_transports title: Transports --- # Akka.Remote Transports In the [Akka.Remote overview](index.md) we introduced the concept of "transports" for Akka.Remote. -> A"transport" refers to an actual network transport, such as TCP or UDP. By default Akka.Remote uses a [Helios](http://helios-io.github.io/ "Helios - Reactive socket middleware for .NET") TCP transport, but you could write your own transport and use that instead of you wish. +> A"transport" refers to an actual network transport, such as TCP or UDP. By default Akka.Remote uses a [DotNetty](https://github.com/Azure/DotNetty") TCP transport, but you could write your own transport and use that instead of you wish. In this section we'll expand a bit more on what transports are and how Akka.Remote can support multiple transports simultaneously. @@ -19,7 +19,7 @@ Transports in Akka.Remote are abstractions on top of actual network transports, Transports **do not need to care** about: * **Serialization** - that's handled by Akka.NET itself; * **Connection-oriented behavior** - the assocation process inside Akka.Remote ensures this, even over connectionless transports like UDP; -* **Reliable delivery** - for system messages this is handled by Akka.Remote and for user-defined messages this is taken care of at the application level through something like the [`AtLeastOnceDeliveryActor` class](http://api.getakka.net/docs/stable/html/2FD30363.htm), part of Akka.Persistence; +* **Reliable delivery** - for system messages this is handled by Akka.Remote and for user-defined messages this is taken care of at the application level through something like the [`AtLeastOnceDeliveryActor` class](xref:at-least-once-delivery), part of Akka.Persistence; * **Handling network failures** - all a transport needs to do is forward that information back up to Akka.Remote. Transports **do need to care** about: @@ -33,12 +33,12 @@ Transports **do need to care** about: Transports are just plumbing for Akka.Remote - they carry out their tasks and keep things simple and performant. ## Akka.Remote's Built-in Transports -Out of the box Akka.NET uses a socket-based transport built on top of the [Helios socket library](http://helios-io.github.io/). +Out of the box Akka.NET uses a socket-based transport built on top of the [DotNetty](https://github.com/Azure/DotNetty). > [!NOTE] -> Helios supports both TCP and UDP, but currently only TCP support is included within Akka.NET. TCP is what most Akka.Remote and Akka.Cluster users use. +> DotNetty supports both TCP and UDP, but currently only TCP support is included within Akka.NET. TCP is what most Akka.Remote and Akka.Cluster users use. -To enable the Helios TCP transport, we need to add a section for it inside our `remote` section in [HOCON configuration](/concepts/configuration.md): +To enable the DotNetty TCP transport, we need to add a section for it inside our `remote` section in [HOCON configuration](xref:configuration): ```xml akka { @@ -46,7 +46,7 @@ akka { provider = "Akka.Remote.RemoteActorRefProvider, Akka.Remote" } remote { - helios.tcp { + dot-netty.tcp { port = 8081 #bound to a specific port hostname = localhost } @@ -77,7 +77,7 @@ akka{ You'd define a custom HOCON section (`akka.remote.google-quic`) and let Akka.Remote know that it should read that section for a transport definition inside `akka.remote.enabled-transports`. > [!NOTE] -> To implement a custom transport yourself, you need to implement the [`Akka.Remote.Transport.Transport` abstract class](http://api.getakka.net/docs/stable/html/F60EF1D2.htm). +> To implement a custom transport yourself, you need to implement the [`Akka.Remote.Transport.Transport` abstract class](xref:Akka.Remote.Transport.Transport). One important thing to note is the `akka.remote.google-quic.transport-protocol` setting - this specifices the address scheme you will use to address remote actors via the Quic protocol. @@ -91,17 +91,17 @@ So the protocol you use in your remote `ActorSelection`s will need to use the st ## Running Multiple Transports Simultaneously One of the most productive features of Akka.Remote is its ability to allow you to support multiple transports simultaneously within a single `ActorSystem`. -Suppose we added UDP support for the built-in Helios transport - here's what running both a UDP and TCP transport at the same time would look like in HOCON configuration. +Suppose we created support for an http transport - here's what running both the DotNetty TCP transport and our *imaginary* http transport at the same time would look like in HOCON configuration. ```xml akka{ remote { - enabled-transports = ["akka.remote.helios.tcp", "akka.remote.helios.udp"] - helios.tcp { + enabled-transports = ["akka.remote.dot-netty.tcp", "akka.remote.magic.http"] + dot-netty.tcp { port = 8081 hostname = localhost } - helios.udp { + magic.http { port = 8082 # needs to be on a different port or IP than TCP hostname = localhost } @@ -109,15 +109,15 @@ akka{ } ``` -Both TCP and UDP are enabled in this scenario. But how do I know which transport is being used when I send a message to a `RemoteActorRef`? That's indicated by the protocol scheme used in the `Address` of the remote actor: +Both TCP and HTTP are enabled in this scenario. But how do I know which transport is being used when I send a message to a `RemoteActorRef`? That's indicated by the protocol scheme used in the `Address` of the remote actor: - akka.tcp://MySystem@localhost:8081/user/actor #helios.tcp - akka.udp://MySystem@localhost:8082/user/actor #helios.udp + akka.tcp://MySystem@localhost:8081/user/actor #dot-netty.tcp + akka.udp://MySystem@localhost:8082/user/actor #magic.http -So if you want to send a message to a remote actor over UDP, you'd write something like this: +So if you want to send a message to a remote actor over HTTP, you'd write something like this: ```csharp -var as = MyActorSystem.ActorSelection("akka.udp://RemoteSystem@localhost:8082/user/actor"); +var as = MyActorSystem.ActorSelection("akka.http://RemoteSystem@localhost:8082/user/actor"); as.Tell("remote message!"); //delivers message to remote system, if they're also using this transport ``` @@ -134,13 +134,13 @@ One common DevOps issue that comes up often with Akka.Remote is something along This can be solved through a built-in configuration property that is supported on every Akka.Remote transport, including third-party ones called the `public-hostname` property. -For instance, we can bind a Helios TCP transport to listen on all addresses (`0.0.0.0`) so we can accept messages from multiple network interfaces (which is more common in server-side environments than you might think) but still register itself as listening on `machine1.foobar.com`: +For instance, we can bind a DotNetty TCP transport to listen on all addresses (`0.0.0.0`) so we can accept messages from multiple network interfaces (which is more common in server-side environments than you might think) but still register itself as listening on `machine1.foobar.com`: ```xml akka{ remote { - enabled-transports = ["akka.remote.helios.tcp", "akka.remote.helios.udp"] - helios.tcp { + enabled-transports = ["akka.remote.dot-netty.tcp", "akka.remote.dot-netty.udp"] + dot-netty.tcp { port = 8081 hostname = 0.0.0.0 # listen on all interfaces public-hostname = "machine1.foobar.com" @@ -149,11 +149,11 @@ akka{ } ``` -This configuration allows the `ActorSystem`'s Helios TCP transport to listen on all interfaces, but when it associates with a remote system it'll tell the remote system that it's address is actually `machine1.foobar.com`. +This configuration allows the `ActorSystem`'s DotNetty TCP transport to listen on all interfaces, but when it associates with a remote system it'll tell the remote system that it's address is actually `machine1.foobar.com`. Why is this distinction important? Why do we care about registering an publicly accessible hostname with our `ActorSystem`? Because in the event that other systems need to connect or reconnect to this process, *they need to have a reachable address.* By default, Akka.Remote assumes that `hostname` is publicly accessible and will use that as the `public-hostname` value. But in the even that it's not AND some of your Akka.NET applications might need to contact this process then you need to set a publicly accessible hostname. ## Additional Resources -* [Message Framing](http://blog.stephencleary.com/2009/04/message-framing.html) by Stephen Cleary \ No newline at end of file +* [Message Framing](http://blog.stephencleary.com/2009/04/message-framing.html) by Stephen Cleary diff --git a/docs/articles/streams/basics.md b/docs/articles/streams/basics.md index 4e2edfce785..573f1dfb4de 100644 --- a/docs/articles/streams/basics.md +++ b/docs/articles/streams/basics.md @@ -18,7 +18,7 @@ An active process that involves moving and transforming data. **Element** An element is the processing unit of streams. All operations transform and transfer elements from upstream to downstream. -Buffer sizes are always expressed as number of elements independently form the actual size of the elements. +Buffer sizes are always expressed as number of elements independently from the actual size of the elements. **Back-pressure** A means of flow-control, a way for consumers of data to notify a producer about their current availability, effectively slowing down the upstream producer to match their consumption speeds. @@ -196,12 +196,12 @@ var otherSink = Flow.Create().AlsoTo(sink).To(Sink.Ignore()); Source.From(Enumerable.Range(1, 6)).To(otherSink); ``` -####Illegal stream elements +#### Illegal stream elements In accordance to the Reactive Streams specification ([Rule 2.13] (https://github.com/reactive-streams/reactive-streams-jvm#2.13>)) Akka Streams do not allow ``null`` to be passed through the stream as an element. In case you want to model the concept of absence of a value we recommend using ``Akka.Streams.Util.Option`` or ``Akka.Util.Either``. -#Back-pressure explained +# Back-pressure explained Akka Streams implement an asynchronous non-blocking back-pressure protocol standardised by the [Reactive Streams](http://reactive-streams.org/) specification, which Akka is a founding member of. @@ -230,7 +230,7 @@ with the upstream production rate or not. To illustrate this further let us consider both problem situations and how the back-pressure protocol handles them: -####Slow Publisher, fast Subscriber +#### Slow Publisher, fast Subscriber This is the happy case of course – we do not need to slow down the Publisher in this case. However signalling rates are rarely constant and could change at any point in time, suddenly ending up in a situation where the Subscriber is now slower than the Publisher. In order to safeguard from these situations, the back-pressure protocol must still be enabled @@ -245,7 +245,7 @@ that the Publisher should not ever have to wait (be back-pressured) with publish As we can see, in this scenario we effectively operate in so called push-mode since the Publisher can continue producing elements as fast as it can, since the pending demand will be recovered just-in-time while it is emitting elements. -####Fast Publisher, slow Subscriber +#### Fast Publisher, slow Subscriber This is the case when back-pressuring the ``Publisher`` is required, because the ``Subscriber`` is not able to cope with the rate at which its upstream would like to emit data elements. @@ -260,7 +260,7 @@ it will have to abide to this back-pressure by applying one of the below strateg As we can see, this scenario effectively means that the ``Subscriber`` will *pull* the elements from the Publisher – this mode of operation is referred to as pull-based back-pressure. -#Stream Materialization +# Stream Materialization When constructing flows and graphs in Akka Streams think of them as preparing a blueprint, an execution plan. Stream materialization is the process of taking a stream description (the graph) and allocating all the necessary resources @@ -279,7 +279,7 @@ which will be running on the thread pools they have been configured to run on - > [!NOTE] > Reusing *instances* of linear computation stages (Source, Sink, Flow) inside composite Graphs is legal, yet will materialize that stage multiple times. -####Operator Fusion +#### Operator Fusion Akka Streams contains an initial version of stream operator fusion support. This means that the processing steps of a flow or stream graph can be executed within the same Actor and has three consequences: @@ -327,7 +327,7 @@ The new fusing behavior can be disabled by setting the configuration parameter ` In that case you can still manually fuse those graphs which shall run on less Actors. With the exception of the `SslTlsStage` and the ``GroupBy`` operator all built-in processing stages can be fused. -####Combining materialized values +#### Combining materialized values Since every processing stage in Akka Streams can provide a materialized value after being materialized, it is necessary to somehow express how these values should be composed to a final value when we plug these stages together. For this, many combinator methods have variants that take an additional argument, a function, that will be used to combine the @@ -402,7 +402,7 @@ RunnableGraph, ICancelable, Task>> r12 = > For details see [Accessing the materialized value inside the Graph](workingwithgraphs.md#accessing-the-materialized-value-inside-the-graph). -#Stream ordering +# Stream ordering In Akka Streams almost all computation stages *preserve input order* of elements. This means that if inputs ``{IA1,IA2,...,IAn}`` "cause" outputs ``{OA1,OA2,...,OAk}`` and inputs ``{IB1,IB2,...,IBm}`` "cause" outputs ``{OB1,OB2,...,OBl}`` and all of ``IAi`` happened before all ``IBi`` then ``OAi`` happens before ``OBi``. diff --git a/docs/articles/streams/buffersandworkingwithrate.md b/docs/articles/streams/buffersandworkingwithrate.md index ff13b3dba95..ddbe1c1931a 100644 --- a/docs/articles/streams/buffersandworkingwithrate.md +++ b/docs/articles/streams/buffersandworkingwithrate.md @@ -3,10 +3,10 @@ layout: docs.hbs title: Buffers and working with rate --- -#Buffers and working with rate +# Buffers and working with rate When upstream and downstream rates differ, especially when the throughput has spikes, it can be useful to introduce buffers in a stream. In this chapter we cover how buffers are used in Akka Streams. -##Buffers for asynchronous stages +## Buffers for asynchronous stages In this section we will discuss internal buffers that are introduced as an optimization when using asynchronous stages. To run a stage asynchronously it has to be marked explicitly as such using the .async method. Being run asynchronously means that a stage, after handing out an element to its downstream consumer is able to immediately process the next message. To demonstrate what we mean by this, let's take a look at the following example: ```csharp @@ -33,7 +33,7 @@ While pipelining in general increases throughput, in practice there is a cost of While this internal protocol is mostly invisible to the user (apart form its throughput increasing effects) there are situations when these details get exposed. In all of our previous examples we always assumed that the rate of the processing chain is strictly coordinated through the backpressure signal causing all stages to process no faster than the throughput of the connected chain. There are tools in Akka Streams however that enable the rates of different segments of a processing chain to be "detached" or to define the maximum throughput of the stream through external timing sources. These situations are exactly those where the internal batching buffering strategy suddenly becomes non-transparent. -##Internal buffers and their effect +## Internal buffers and their effect As we have explained, for performance reasons Akka Streams introduces a buffer for every asynchronous processing stage. The purpose of these buffers is solely optimization, in fact the size of 1 would be the most natural choice if there would be no need for throughput improvements. Therefore it is recommended to keep these buffer sizes small, and increase them only to a level suitable for the throughput requirements of the application. Default buffer sizes can be set through configuration: ```hocon akka.stream.materializer.max-input-buffer-size = 16 @@ -80,7 +80,7 @@ Running the above example one would expect the number 3 to be printed in every 3 > [!NOTE] > In general, when time or rate driven processing stages exhibit strange behavior, one of the first solutions to try should be to decrease the input buffer of the affected elements to 1. -##Buffers in Akka Streams +## Buffers in Akka Streams In this section we will discuss explicit user defined buffers that are part of the domain logic of the stream processing pipeline of an application. The example below will ensure that 1000 jobs (but not more) are dequeued from an external (imaginary) system and stored locally in memory -- relieving the external system: @@ -110,8 +110,8 @@ If our imaginary external job provider is a client using our API, we might want ```csharp jobs.buffer(1000, OverflowStrategy.fail) ``` -##Rate transformation -###Understanding conflate +## Rate transformation +### Understanding conflate When a fast producer can not be informed to slow down by backpressure or some other signal, conflate might be useful to combine elements from a producer until a demand signal comes from a consumer. Below is an example snippet that summarizes fast stream of elements to a standard deviation, mean and count of elements that have arrived while the stats have been calculated. @@ -140,7 +140,7 @@ Another possible use of `conflate` is to not consider all elements for summary w return agg; }).Concat(identity); ``` -###Understanding expand +### Understanding expand Expand helps to deal with slow producers which are unable to keep up with the demand coming from consumers. Expand allows to extrapolate a value to be sent as an element to a consumer. As a simple use of expand here is a flow that sends the same element to consumer when producer does not send any new elements. diff --git a/docs/articles/streams/builtinstages.md b/docs/articles/streams/builtinstages.md index 7364a9ff463..067d81a4898 100644 --- a/docs/articles/streams/builtinstages.md +++ b/docs/articles/streams/builtinstages.md @@ -3,12 +3,12 @@ layout: docs.hbs title: Overview of built-in stages and their semantics --- -#Source stages +# Source stages These built-in sources are available from ``akka.stream.scaladsl.Source``: -####FromEnumerator +#### FromEnumerator Stream the values from an ``Enumerator``, requesting the next value when there is demand. The enumerator will be created anew for each materialization, which is the reason the method takes a function rather than an enumerator directly. @@ -19,7 +19,7 @@ If the enumerator perform blocking operations, make sure to run it on a separate **completes** when the enumerator reaches its end -####From +#### From Stream the values of an ``IEnumerable``. @@ -28,7 +28,7 @@ Stream the values of an ``IEnumerable``. **completes** when the last element of the enumerable has been emitted -####Single +#### Single Stream a single object @@ -36,7 +36,7 @@ Stream a single object **completes** when the single value has been emitted -####Repeat +#### Repeat Stream a single object repeatedly @@ -44,7 +44,7 @@ Stream a single object repeatedly **completes** never -####Cycle +#### Cycle Stream iterator in cycled manner. Internally new iterator is being created to cycle the one provided via argument meaning when original iterator runs out of elements process will start all over again from the beginning of the iterator @@ -55,7 +55,7 @@ exception. **completes** never -####Tick +#### Tick A periodical repetition of an arbitrary object. Delay of first tick is specified separately from interval of the following ticks. @@ -64,7 +64,7 @@ separately from interval of the following ticks. **completes** never -####FromTask +#### FromTask Send the single value of the ``Task`` when it completes and there is demand. If the task fails the stream is failed with that exception. @@ -73,7 +73,7 @@ If the task fails the stream is failed with that exception. **completes** after the task has completed -####Unfold +#### Unfold Stream the result of a function as long as it returns not ``null``, the value inside the option consists of a tuple where the first value is a state passed back into the next call to the function allowing @@ -85,7 +85,7 @@ Can be used to implement many stateful sources without having to touch the more **completes** when the unfold function returns an null value -####UnfoldAsync +#### UnfoldAsync Just like ``Unfold`` but the fold function returns a ``Task`` which will cause the source to complete or emit when it completes. @@ -96,7 +96,7 @@ Can be used to implement many stateful sources without having to touch the more **completes** when the task returned by the unfold function completes with an null value -####Empty +#### Empty Complete right away without ever emitting any elements. Useful when you have to provide a source to an API but there are no elements to emit. @@ -105,7 +105,7 @@ an API but there are no elements to emit. **completes** directly -####Maybe +#### Maybe Materialize a ``TaskCompletionSource`` that if completed with a ``T`` will emit that `T` and then complete the stream, or if completed with ``null`` complete the stream right away. @@ -114,7 +114,7 @@ the stream, or if completed with ``null`` complete the stream right away. **completes** after emitting not null value, or directly if the promise is completed with null value -####Failed +#### Failed Fail directly with a user specified exception. @@ -122,7 +122,15 @@ Fail directly with a user specified exception. **completes** fails the stream directly with the given exception -####ActorPublisher +#### Lazily + +Defers creation and materialization of a `Source` until there is demand. + +**emits** depends on the wrapped `Source` + +**completes** depends on the wrapped `Source` + +#### ActorPublisher Wrap an actor extending ``ActorPublisher`` as a source. @@ -130,7 +138,7 @@ Wrap an actor extending ``ActorPublisher`` as a source. **completes** when the actor stops -####ActorRef +#### ActorRef Materialize an ``IActorRef``, sending messages to it will emit them on the stream. The actor contain a buffer but since communication is one way, there is no back pressure. Handling overflow is done by either dropping @@ -140,7 +148,7 @@ elements or failing the stream, the strategy is chosen by the user. **completes** when the actorref is sent ``Akka.Actor.Status.Success`` or ``PoisonPill`` -####Combine +#### Combine Combine several sources, using a given strategy such as merge or concat, into one source. @@ -148,7 +156,7 @@ Combine several sources, using a given strategy such as merge or concat, into on **completes** when all sources has completed -####UnfoldResource +#### UnfoldResource Wrap any resource that can be opened, queried for next element (in a blocking way) and closed using three distinct functions into a source. @@ -156,7 +164,7 @@ Wrap any resource that can be opened, queried for next element (in a blocking wa **completes** when read function returns ``None`` -####UnfoldResourceAsync +#### UnfoldResourceAsync Wrap any resource that can be opened, queried for next element (in a blocking way) and closed using three distinct functions into a source. Functions return ``Task`` to achieve asynchronous processing @@ -165,7 +173,7 @@ Functions return ``Task`` to achieve asynchronous processing **completes** when ``Task`` from read function returns ``None`` -####Queue +#### Queue Materialize a ``SourceQueue`` onto which elements can be pushed for emitting from the source. The queue contains a buffer, if elements are pushed onto the queue faster than the source is consumed the overflow will be handled with @@ -176,17 +184,17 @@ a strategy specified by the user. Functionality for tracking when an element has **completes** when downstream completes -####AsSubscriber +#### AsSubscriber Integration with Reactive Streams, materializes into a ``Reactive.Streams.ISubscriber``. -####FromPublisher +#### FromPublisher Integration with Reactive Streams, subscribes to a ``Reactive.Streams.IPublisher``. -####ZipN +#### ZipN Combine the elements of multiple streams into a stream of sequences. @@ -195,7 +203,7 @@ Combine the elements of multiple streams into a stream of sequences. **completes** when any upstream completes -####ZipWithN +#### ZipWithN Combine the elements of multiple streams into a stream of sequences using a combiner function. @@ -204,12 +212,12 @@ Combine the elements of multiple streams into a stream of sequences using a comb **completes** when any upstream completes -#Sink stages +# Sink stages These built-in sinks are available from ``Akka.Stream.DSL.Sink``: -####First +#### First Materializes into a ``Task`` which completes with the first value arriving, after this the stream is canceled. If no element is emitted, the task is be failed. @@ -218,7 +226,7 @@ after this the stream is canceled. If no element is emitted, the task is be fail **backpressures** never -####FirstOrDefault +#### FirstOrDefault Materializes into a ``Task`` which completes with the first value arriving, or a ``default(T)`` if the stream completes without any elements emitted. @@ -226,7 +234,7 @@ or a ``default(T)`` if the stream completes without any elements emitted. **backpressures** never -####Last +#### Last Materializes into a ``Task`` which will complete with the last value emitted when the stream completes. If the stream completes with no elements the task is failed. @@ -235,7 +243,7 @@ completes. If the stream completes with no elements the task is failed. **backpressures** never -####LasrOrDefault +#### LasrOrDefault Materialize a ``Task`` which completes with the last value emitted when the stream completes. if the stream completes with no elements the task is @@ -245,7 +253,7 @@ completed with default(T). **backpressures** never -####Ignore +#### Ignore Consume all elements but discards them. Useful when a stream has to be consumed but there is no use to actually do anything with the elements. @@ -254,13 +262,13 @@ do anything with the elements. **backpressures** never -####Cancelled +#### Cancelled Immediately cancel the stream **cancels** immediately -####Seq +#### Seq Collect values emitted from the stream into a collection, the collection is available through a ``Task`` or which completes when the stream completes. Note that the collection is bounded to ``int.MaxValue``, @@ -268,7 +276,7 @@ if more element are emitted the sink will cancel the stream **cancels** If too many values are collected -####Foreach +#### Foreach Invoke a given procedure for each element received. Note that it is not safe to mutate shared state from the procedure. @@ -282,7 +290,7 @@ Note that it is not safe to mutate state from the procedure. **backpressures** when the previous procedure invocation has not yet completed -####ForeachParallel +#### ForeachParallel Like ``Foreach`` but allows up to ``parallellism`` procedure calls to happen in parallel. @@ -291,7 +299,7 @@ Like ``Foreach`` but allows up to ``parallellism`` procedure calls to happen in **backpressures** when the previous parallel procedure invocations has not yet completed -####OnComplete +#### OnComplete Invoke a callback when the stream has completed or failed. @@ -300,7 +308,7 @@ Invoke a callback when the stream has completed or failed. **backpressures** never -####Aggregate +#### Aggregate Fold over emitted element with a function, where each invocation will get the new element and the result from the previous fold invocation. The first invocation will be provided the ``zero`` value. @@ -314,7 +322,7 @@ between invocations. **backpressures** when the previous fold function invocation has not yet completed -####Sum +#### Sum Apply a reduction function on the incoming elements and pass the result to the next invocation. The first invocation receives the two first elements of the flow. @@ -326,7 +334,7 @@ Materializes into a task that will be completed by the last result of the reduct **backpressures** when the previous reduction function invocation has not yet completed -####Combine +#### Combine Combine several sinks into one using a user specified strategy @@ -335,7 +343,7 @@ Combine several sinks into one using a user specified strategy **backpressures** depends on the strategy -####ActorRef +#### ActorRef Send the elements from the stream to an ``IActorRef``. No backpressure so care must be taken to not overflow the inbox. @@ -344,7 +352,7 @@ Send the elements from the stream to an ``IActorRef``. No backpressure so care m **backpressures** never -####ActorRefWithAck +#### ActorRefWithAck Send the elements from the stream to an ``IActorRef`` which must then acknowledge reception after completing a message, to provide back pressure onto the sink. @@ -354,7 +362,7 @@ to provide back pressure onto the sink. **backpressures** when the actor acknowledgement has not arrived -####ActorSubscriber +#### ActorSubscriber Create an actor from a ``Props`` upon materialization, where the actor implements ``ActorSubscriber``, which will receive the elements from the stream. @@ -366,25 +374,25 @@ Materializes into an ``IActorRef`` to the created actor. **backpressures** depends on the actor implementation -####AsPublisher +#### AsPublisher Integration with Reactive Streams, materializes into a ``Reactive.Streams.IPublisher``. -####FromSubscriber +#### FromSubscriber Integration with Reactive Streams, wraps a ``Reactive.Streams.ISubscriber`` as a sink -#Additional Sink and Source converters +# Additional Sink and Source converters Sources and sinks for integrating with ``System.IO.Stream`` can be found on ``StreamConverters``. As they are blocking APIs the implementations of these stages are run on a separate dispatcher configured through the ``akka.stream.blocking-io-dispatcher``. -####FromOutputStream +#### FromOutputStream Create a sink that wraps an ``Stream``. Takes a function that produces an ``Stream``, when the sink is materialized the function will be called and bytes sent to the sink will be written to the returned ``Stream``. @@ -398,7 +406,7 @@ to handle multiple invocations. The ``Stream`` will be closed when the stream that flows into the ``Sink`` is completed, and the ``Sink`` will cancel its inflow when the ``Stream`` is no longer writable. -####AsInputStream +#### AsInputStream Create a sink which materializes into an ``Stream`` that can be read to trigger demand through the sink. Bytes emitted through the stream will be available for reading through the ``Stream`` @@ -406,7 +414,7 @@ Bytes emitted through the stream will be available for reading through the ``Str The ``Stream`` will be ended when the stream flowing into this ``Sink`` completes, and the closing the ``Stream`` will cancel the inflow of this ``Sink``. -####FromInputStream +#### FromInputStream Create a source that wraps an ``Stream``. Takes a function that produces an ``Stream``, when the source is materialized the function will be called and bytes from the ``Stream`` will be emitted into the stream. @@ -420,7 +428,7 @@ to handle multiple invocations. The ``Stream`` will be closed when the ``Source`` is canceled from its downstream, and reaching the end of the ``Stream`` will complete the ``Source``. -####AsOutputStream +#### AsOutputStream Create a source that materializes into an ``Stream``. When bytes are written to the ``Stream`` they are emitted from the source @@ -432,12 +440,12 @@ File IO Sinks and Sources ------------------------- Sources and sinks for reading and writing files can be found on ``FileIO``. -####FromFile +#### FromFile Emit the contents of a file, as ``ByteString`` s, materializes into a ``Task`` which will be completed with a ``IOResult`` upon reaching the end of the file or if there is a failure. -####ToFile +#### ToFile Create a sink which will write incoming ``ByteString`` s to a given file. @@ -467,7 +475,7 @@ However, these rate transformations are data-driven, i.e. it is the incoming ele rate is affected. This is in contrast with [Backpressure aware stages](#backpressure-aware-stages) which can change their processing behavior depending on being backpressured by downstream or not. -####Select +#### Select Transform each element in the stream by calling a mapping function with it and passing the returned value downstream. @@ -477,7 +485,7 @@ Transform each element in the stream by calling a mapping function with it and p **completes** when upstream completes -####SelectMany +#### SelectMany Transform each element into zero or more elements that are individually passed downstream. @@ -487,7 +495,7 @@ Transform each element into zero or more elements that are individually passed d **completes** when upstream completes and all remaining elements has been emitted -####StatefulSelectMany +#### StatefulSelectMany Transform each element into zero or more elements that are individually passed downstream. The difference to ``SelectMany`` is that the transformation function is created from a factory for every materialization of the flow. @@ -498,7 +506,7 @@ the transformation function is created from a factory for every materialization **completes** when upstream completes and all remaining elements has been emitted -####Where +#### Where Filter the incoming elements using a predicate. If the predicate returns true the element is passed downstream, if it returns false the element is discarded. @@ -509,7 +517,7 @@ it returns false the element is discarded. **completes** when upstream completes -####Collect +#### Collect Apply a partial function to each incoming element, if the partial function is defined for a value the returned value is passed downstream. Can often replace ``Where`` followed by ``Select`` to achieve the same in one single stage. @@ -520,7 +528,7 @@ value is passed downstream. Can often replace ``Where`` followed by ``Select`` t **completes** when upstream completes -####Grouped +#### Grouped Accumulate incoming events until the specified number of elements have been accumulated and then pass the collection of elements downstream. @@ -531,7 +539,7 @@ elements downstream. **completes** when upstream completes -####Sliding +#### Sliding Provide a sliding window over the incoming stream and pass the windows as groups of elements downstream. @@ -543,8 +551,7 @@ Note: the last window might be smaller than the requested size due to end of str **completes** when upstream completes - -####Scan +#### Scan Emit its current value which starts at ``zero`` and then applies the current and next value to the given function emitting the next current value. @@ -558,7 +565,17 @@ the second element is required from downstream. **completes** when upstream completes -####Aggregate +#### ScanAsync + +Just like `Scan` but receiving a function that results in a `Task` to the next value. + +**emits** when the `Task` resulting from the function scanning the element resolves to the next value + +**backpressures** when downstream backpressures + +**completes** when upstream completes and the last `Task` is resolved + +#### Aggregate Start with current value ``zero`` and then apply the current and next value to the given function, when upstream complete the current value is emitted downstream. @@ -569,7 +586,17 @@ complete the current value is emitted downstream. **completes** when upstream completes -####Skip +#### AggregateAsync + +Just like `Aggregate` but receiving a function that results in a `Task` to the next value. + +**emits** when upstream completes and the last `Task` is resolved + +**backpressures** when downstream backpressures + +**completes** when upstream completes and the last `Task` is resolved + +#### Skip Skip ``n`` elements and then pass any subsequent element downstream. @@ -579,7 +606,7 @@ Skip ``n`` elements and then pass any subsequent element downstream. **completes** when upstream completes -####Take +#### Take Pass ``n`` incoming elements downstream and then complete @@ -590,7 +617,7 @@ Pass ``n`` incoming elements downstream and then complete **completes** when the defined number of elements has been taken or upstream completes -####TakeWhile +#### TakeWhile Pass elements downstream as long as a predicate function return true for the element include the element when the predicate first return false and then complete. @@ -601,7 +628,7 @@ when the predicate first return false and then complete. **completes** when predicate returned false or upstream completes -####SkipWhile +#### SkipWhile Skip elements as long as a predicate function return true for the element @@ -611,27 +638,64 @@ Skip elements as long as a predicate function return true for the element **completes** when upstream completes -####Recover +#### Recover Allow sending of one last element downstream when a failure has happened upstream. +Throwing an exception inside `Recover` _will_ be logged on ERROR level automatically. + **emits** when the element is available from the upstream or upstream is failed and pf returns an element **backpressures** when downstream backpressures, not when failure happened **completes** when upstream completes or upstream failed with exception pf can handle -####RecoverWith +#### RecoverWith Allow switching to alternative Source when a failure has happened upstream. +Throwing an exception inside `RecoverWith` _will_ be logged on ERROR level automatically. + **emits** the element is available from the upstream or upstream is failed and pf returns alternative Source **backpressures** downstream backpressures, after failure happened it backprssures to alternative Source **completes** upstream completes or upstream failed with exception pf can handle -####Detach +#### RecoverWithRetries + +RecoverWithRetries allows to switch to alternative Source on flow failure. It will stay in effect after +a failure has been recovered up to `attempts` number of times so that each time there is a failure +it is fed into the `function` and a new Source may be materialized. Note that if you pass in 0, this won't +attempt to recover at all. Passing -1 will behave exactly the same as `RecoverWith`. + +Since the underlying failure signal OnError arrives out-of-band, it might jump over existing elements. +This stage can recover the failure signal, but not the skipped elements, which will be dropped. + +**emits** when element is available from the upstream or upstream is failed and element is available from alternative Source + +**backpressures** when downstream backpressures + +**completes** when upstream completes or upstream failed with exception function can handle + +#### SelectError + +While similar to `Recover` this stage can be used to transform an error signal to a different one *without* logging +it as an error in the process. So in that sense it is NOT exactly equivalent to ``Recover(e -> throw e2)`` since recover +would log the `e2` error. + +Since the underlying failure signal OnError arrives out-of-band, it might jump over existing elements. +This stage can recover the failure signal, but not the skipped elements, which will be dropped. + +Similarily to `Recover` throwing an exception inside `SelectError` _will_ be logged on ERROR level automatically. + +**emits** when element is available from the upstream or upstream is failed and function returns an element + +**backpressures** when downstream backpressures + +**completes** when upstream completes or upstream failed with exception function can handle + +#### Detach Detach upstream demand from downstream demand without detaching the stream rates. @@ -642,7 +706,7 @@ Detach upstream demand from downstream demand without detaching the stream rates **completes** when upstream completes -####Throttle +#### Throttle Limit the throughput to a specific number of elements per time unit, or a specific total cost per time unit, where a function has to be provided to calculate the individual cost of each element. @@ -654,13 +718,13 @@ a function has to be provided to calculate the individual cost of each element. **completes** when upstream completes -#Asynchronous processing stages +# Asynchronous processing stages These stages encapsulate an asynchronous computation, properly handling backpressure while taking care of the asynchronous operation at the same time (usually handling the completion of a Task). -####SelectAsync +#### SelectAsync Pass incoming elements to a function that return a ``Task`` result. When the task arrives the result is passed downstream. Up to ``n`` elements can be processed concurrently, but regardless of their completion time the incoming @@ -674,7 +738,7 @@ If a Task fails, the stream also fails (unless a different supervision strategy **completes** when upstream completes and all tasks has been completed and all elements has been emitted -####SelectAsyncUnordered +#### SelectAsyncUnordered Like ``SelectAsync`` but ``Task`` results are passed downstream as they arrive regardless of the order of the elements that triggered them. @@ -688,11 +752,11 @@ If a Task fails, the stream also fails (unless a different supervision strategy **completes** upstream completes and all tasks has been completed and all elements has been emitted -#Timer driven stages +# Timer driven stages These stages process elements using timers, delaying, dropping or grouping elements for certain time durations. -####TakeWithin +#### TakeWithin Pass elements downstream within a timeout and then complete. @@ -703,7 +767,7 @@ Pass elements downstream within a timeout and then complete. **completes** upstream completes or timer fires -####SkipWithin +#### SkipWithin Skip elements until a timeout has fired @@ -713,7 +777,7 @@ Skip elements until a timeout has fired **completes** upstream completes -####GroupedWithin +#### GroupedWithin Chunk up the stream into groups of elements received within a time window, or limited by the given number of elements, whichever happens first. @@ -725,7 +789,7 @@ whichever happens first. **completes** when upstream completes -####InitialDelay +#### InitialDelay Delay the initial element by a user specified duration from stream materialization. @@ -736,7 +800,7 @@ Delay the initial element by a user specified duration from stream materializati **completes** when upstream completes -####Delay +#### Delay Delay every element passed through with a specific duration. @@ -747,11 +811,11 @@ Delay every element passed through with a specific duration. **completes** when upstream completes and buffered elements has been drained -#Backpressure aware stages +# Backpressure aware stages These stages are aware of the backpressure provided by their downstreams and able to adapt their behavior to that signal. -####Conflate +#### Conflate Allow for a slower downstream by passing incoming elements and a summary into an aggregate function as long as there is backpressure. The summary value must be of the same type as the incoming elements, for example the sum or @@ -763,7 +827,7 @@ average of incoming numbers, if aggregation should lead to a different type ``Co **completes** when upstream completes -####ConflateWithSeed +#### ConflateWithSeed Allow for a slower downstream by passing incoming elements and a summary into an aggregate function as long as there is backpressure. When backpressure starts or there is no backpressure element is passed into a ``seed`` function to @@ -775,7 +839,7 @@ transform it to the summary type. **completes** when upstream completes -####Batch +#### Batch Allow for a slower downstream by passing incoming elements and a summary into an aggregate function as long as there is backpressure and a maximum number of batched elements is not yet reached. When the maximum number is reached and @@ -794,7 +858,7 @@ aggregated to the batched value. **completes** when upstream completes and a "possibly pending" element was drained -####BatchWeighted +#### BatchWeighted Allow for a slower downstream by passing incoming elements and a summary into an aggregate function as long as there is backpressure and a maximum weight batched elements is not yet reached. The weight of each element is determined by @@ -810,7 +874,7 @@ aggregated to the batched value. **completes** upstream completes and a "possibly pending" element was drained -####Expand +#### Expand Allow for a faster downstream by expanding the last incoming element to an ``Enumerator`` @@ -820,7 +884,7 @@ Allow for a faster downstream by expanding the last incoming element to an ``Enu **completes** when upstream completes -####Buffer (Backpressure) +#### Buffer (Backpressure) Allow for a temporarily faster upstream events by buffering ``size`` elements. When the buffer is full backpressure is applied. @@ -831,7 +895,7 @@ is applied. **completes** when upstream completes and buffered elements has been drained -####Buffer (Drop) +#### Buffer (Drop) Allow for a temporarily faster upstream events by buffering ``size`` elements. When the buffer is full elements are dropped according to the specified ``OverflowStrategy``: @@ -847,7 +911,7 @@ dropped according to the specified ``OverflowStrategy``: **completes** upstream completes and buffered elements has been drained -####Buffer (Fail) +#### Buffer (Fail) Allow for a temporarily faster upstream events by buffering ``size`` elements. When the buffer is full the stage fails the flow with a ``BufferOverflowException``. @@ -859,12 +923,12 @@ the flow with a ``BufferOverflowException``. **completes** when upstream completes and buffered elements has been drained -#Nesting and flattening stages +# Nesting and flattening stages These stages either take a stream and turn it into a stream of streams (nesting) or they take a stream that contains nested streams and turn them into a stream of elements instead (flattening). -#PrefixAndTail +# PrefixAndTail Take up to `n` elements from the stream (less than `n` only if the upstream completes before emitting `n` elements) and returns a pair containing a strict sequence of the taken element and a stream representing the remaining elements. @@ -876,7 +940,7 @@ and returns a pair containing a strict sequence of the taken element and a strea **completes** when prefix elements has been consumed and substream has been consumed -####GroupBy +#### GroupBy Demultiplex the incoming stream into separate output streams. @@ -885,7 +949,7 @@ there is an element pending for a group whose substream backpressures **completes** when upstream completes (Until the end of stream it is not possible to know whether new substreams will be needed or not) -####SplitWhen +#### SplitWhen Split off elements into a new substream whenever a predicate function return ``true``. @@ -895,7 +959,7 @@ Split off elements into a new substream whenever a predicate function return ``t **completes** when upstream completes (Until the end of stream it is not possible to know whether new substreams will be needed or not) -####SplitAfter +#### SplitAfter End the current substream whenever a predicate returns ``true``, starting a new substream for the next element. @@ -905,7 +969,7 @@ End the current substream whenever a predicate returns ``true``, starting a new **completes** when upstream completes (Until the end of stream it is not possible to know whether new substreams will be needed or not) -####ConcatMany +#### ConcatMany Transform each input element into a ``Source`` whose elements are then flattened into the output stream through concatenation. This means each source is fully consumed before consumption of the next source starts. @@ -917,7 +981,7 @@ concatenation. This means each source is fully consumed before consumption of th **completes** when upstream completes and all consumed substreams complete -####MergeMany +#### MergeMany Transform each input element into a ``Source`` whose elements are then flattened into the output stream through merging. The maximum number of merged sources has to be specified. @@ -929,11 +993,11 @@ merging. The maximum number of merged sources has to be specified. **completes** when upstream completes and all consumed substreams complete -#Time aware stages +# Time aware stages Those stages operate taking time into consideration. -####InitialTimeout +#### InitialTimeout If the first element has not passed through this stage before the provided timeout, the stream is failed with a ``TimeoutException``. @@ -946,7 +1010,7 @@ with a ``TimeoutException``. **cancels** when downstream cancels -####CompletionTimeout +#### CompletionTimeout If the completion of the stream does not happen until the provided timeout, the stream is failed with a ``TimeoutException``. @@ -959,7 +1023,7 @@ with a ``TimeoutException``. **cancels** when downstream cancels -####IdleTimeout +#### IdleTimeout If the time between two processed elements exceeds the provided timeout, the stream is failed with a ``TimeoutException``. The timeout is checked periodically, so the resolution of the @@ -973,7 +1037,7 @@ check is one period (equals to timeout value). **cancels** when downstream cancels -####BackpressureTimeout +#### BackpressureTimeout If the time between the emission of an element and the following downstream demand exceeds the provided timeout, the stream is failed with a ``TimeoutException``. The timeout is checked periodically, so the resolution of the @@ -987,7 +1051,7 @@ check is one period (equals to timeout value). **cancels** when downstream cancels -####KeepAlive +#### KeepAlive Injects additional (configured) elements if upstream does not emit for a configured amount of time. @@ -999,7 +1063,7 @@ Injects additional (configured) elements if upstream does not emit for a configu **cancels** when downstream cancels -####InitialDelay +#### InitialDelay Delays the initial element by the specified duration. @@ -1012,12 +1076,12 @@ Delays the initial element by the specified duration. **cancels** when downstream cancels -#Fan-in stages +# Fan-in stages These stages take multiple streams as their input and provide a single output combining the elements from all of the inputs in different ways. -####Merge +#### Merge Merge multiple sources. Picks elements randomly if all sources has elements ready. @@ -1027,7 +1091,7 @@ Merge multiple sources. Picks elements randomly if all sources has elements read **completes** when all upstreams complete (This behavior is changeable to completing when any upstream completes by setting ``eagerComplete=true``.) -####MergeSorted +#### MergeSorted Merge multiple sources. Waits for one element to be ready from each input stream and emits the smallest element. @@ -1038,7 +1102,7 @@ smallest element. **completes** when all upstreams complete -####Zip +#### Zip Combines elements from each of multiple sources into tuples and passes the tuples downstream. @@ -1048,7 +1112,7 @@ Combines elements from each of multiple sources into tuples and passes the tuple **completes** when any upstream completes -####ZipWith +#### ZipWith Combines elements from multiple sources through a ``combine`` function and passes the returned value downstream. @@ -1057,9 +1121,19 @@ returned value downstream. **backpressures** when downstream backpressures +**completes** when any upstream completes + +#### ZipWithIndex + +Zips elements of current flow with its indices. + +**emits** when upstream emits an element and is paired with their index + +**backpressures** when downstream backpressures + **completes** when any upstream completes -####Concat +#### Concat After completion of the original upstream the elements of the given source will be emitted. @@ -1069,7 +1143,7 @@ After completion of the original upstream the elements of the given source will **completes** when all upstreams complete -####Prepend +#### Prepend Prepends the given source to the flow, consuming it until completion before the original source is consumed. @@ -1081,7 +1155,7 @@ If materialized values needs to be collected ``prependMat`` is available. **completes** when all upstreams complete -####OrElse +#### OrElse If the primary source completes without emitting any elements, the elements from the secondary source are emitted. If the primary source emits any elements the secondary source is cancelled. @@ -1099,7 +1173,7 @@ is available from the second stream **completes** the primary stream completes after emitting at least one element, when the primary stream completes without emitting and the secondary stream already has completed or when the secondary stream completes -####Interleave +#### Interleave Emits a specifiable number of elements from the original source, then from the provided source and repeats. If one source completes the rest of the other stream will be emitted. @@ -1110,12 +1184,12 @@ source completes the rest of the other stream will be emitted. **completes** when both upstreams have completed -#Fan-out stages +# Fan-out stages These have one input and multiple outputs. They might route the elements between different outputs, or emit elements on multiple outputs at the same time. -####Unzip +#### Unzip Takes a stream of two element tuples and unzips the two elements into two different downstreams. @@ -1125,7 +1199,7 @@ Takes a stream of two element tuples and unzips the two elements into two differ **completes** when upstream completes -####UnzipWith +#### UnzipWith Splits each element of input into multiple downstreams using a function @@ -1135,7 +1209,7 @@ Splits each element of input into multiple downstreams using a function **completes** when upstream completes -####broadcast +#### broadcast Emit each incoming element each of ``n`` outputs. @@ -1145,7 +1219,7 @@ Emit each incoming element each of ``n`` outputs. **completes** when upstream completes -####Balance +#### Balance Fan-out the stream to several streams. Each upstream element is emitted to the first available downstream consumer. @@ -1156,9 +1230,9 @@ Fan-out the stream to several streams. Each upstream element is emitted to the f **completes** when upstream completes -#Watching status stages +# Watching status stages -####WatchTermination +#### WatchTermination Materializes to a ``Task`` that will be completed with Done or failed depending whether the upstream of the stage has been completed or failed. The stage otherwise passes through elements unchanged. @@ -1170,7 +1244,7 @@ The stage otherwise passes through elements unchanged. **completes** when upstream completes -####Monitor +#### Monitor Materializes to a ``FlowMonitor`` that monitors messages flowing through or completion of the stage. The stage otherwise passes through elements unchanged. Note that the ``FlowMonitor`` inserts a memory barrier every time it processes an diff --git a/docs/articles/streams/cookbook.md b/docs/articles/streams/cookbook.md index 357517817c2..30bdac22fd8 100644 --- a/docs/articles/streams/cookbook.md +++ b/docs/articles/streams/cookbook.md @@ -3,7 +3,7 @@ layout: docs.hbs title: Streams Cookbook --- -#Introduction +# Introduction This is a collection of patterns to demonstrate various usage of the Akka Streams API by solving small targeted problems in the format of "recipes". The purpose of this page is to give inspiration and ideas how to approach @@ -17,12 +17,12 @@ as they appear in the main body of documentation. If you need a quick reference of the available processing stages used in the recipes see [Overview of built-in stages and their semantics](builtinstages.md) -#Working with Flows +# Working with Flows In this collection we show simple recipes that involve linear flows. The recipes in this section are rather general, more targeted recipes are available as separate sections ( [Buffers and working with rate](buffersandworkingwithrate.md), [Working with streaming IO](workingwithstreamingio.md)). -####Logging elements of a stream +#### Logging elements of a stream **Situation:** During development it is sometimes helpful to see what happens in a particular section of a stream. @@ -52,7 +52,7 @@ mySource.Log("before-select") mySource.Log("custom", null, Logging.GetLogger(sys, "customLogger")); ``` -####Flattening a stream of sequences +#### Flattening a stream of sequences **Situation:** A stream is given as a stream of sequence of elements, but a stream of elements needed instead, streaming all the nested elements inside the sequences separately. @@ -66,7 +66,7 @@ Source,NotUsed > myData = someDataSource; Source flattened = myData.SelectMany(x => x); ``` -####Draining a stream to a strict collection +#### Draining a stream to a strict collection **Situation:** A possibly unbounded sequence of elements is given as a stream, which needs to be collected into a collection while ensuring boundedness @@ -95,7 +95,7 @@ var limited = mySource.Limit(MAX_ALLOWED_SIZE).RunWith(Sink.Seq(), mater var ignoreOverflow = mySource.Take(MAX_ALLOWED_SIZE).RunWith(Sink.Seq(), materializer); ``` -####Calculating the digest of a ByteString stream +#### Calculating the digest of a ByteString stream **Situation:** A stream of bytes is given as a stream of ``ByteStrings`` and we want to calculate the cryptographic digest of the stream. @@ -157,7 +157,7 @@ var data = Source.Empty(); var digest = data.Via(new DigestCalculator("SHA-256")); ``` -####Parsing lines from a stream of ByteStrings +#### Parsing lines from a stream of ByteStrings **Situation:** A stream of bytes is given as a stream of ``ByteStrings`` containing lines terminated by line ending characters (or, alternatively, containing binary frames delimited by a special delimiter byte sequence) which @@ -172,7 +172,7 @@ var linesStream = rawData .Select(b => b.DecodeString()); ``` -####Implementing reduce-by-key +#### Implementing reduce-by-key **Situation:** Given a stream of elements, we want to calculate some aggregated value on different subgroups of the @@ -245,7 +245,7 @@ var counts = words.Via(ReduceByKey(MaximumDistinctWords, > Please note that the reduce-by-key version we discussed above is sequential in reading the overall input stream, in other words it is **NOT** a parallelization pattern like MapReduce and similar frameworks. -####Sorting elements to multiple groups with groupBy +#### Sorting elements to multiple groups with groupBy **Situation:** The ``GroupBy`` operation strictly partitions incoming elements, each element belongs to exactly one group. Sometimes we want to map elements into multiple groups simultaneously. @@ -278,11 +278,11 @@ var multiGroups = messageAndTopic.GroupBy(2, tuple => tuple.Item2).Select(tuple }); ``` -#Working with Graphs +# Working with Graphs In this collection we show recipes that use stream graph elements to achieve various goals. -####Triggering the flow of elements programmatically +#### Triggering the flow of elements programmatically **Situation:** Given a stream of elements we want to control the emission of those elements according to a trigger signal. In other words, even if the stream would be able to flow (not being backpressured) we want to hold back elements until a @@ -326,7 +326,7 @@ var graph = RunnableGraph.FromGraph(GraphDsl.Create(b => })); ``` -####Balancing jobs to a fixed pool of workers +#### Balancing jobs to a fixed pool of workers **Situation:** Given a stream of jobs and a worker process expressed as a `Flow` create a pool of workers that automatically balances incoming jobs to available workers, then merges the results. @@ -361,12 +361,12 @@ var worker = Flow.Create().Select(j => new Done(j)); var processedJobs = myJobs.Via(Balancer(worker, 3)); ``` -#Working with rate +# Working with rate This collection of recipes demonstrate various patterns where rate differences between upstream and downstream needs to be handled by other strategies than simple backpressure. -####Dropping elements +#### Dropping elements **Situation:** Given a fast producer and a slow consumer, we want to drop elements if necessary to not slow down the producer too much. @@ -385,7 +385,7 @@ var droppyStream = Flow.Create().Conflate((lastMessage, newMessage) => There is a more general version of ``Conflate`` named ``ConflateWithSeed`` that allows to express more complex aggregations, more similar to a ``Aggregate``. -####Dropping broadcast +#### Dropping broadcast **Situation:** The default ``Broadcast`` graph element is properly backpressured, but that means that a slow downstream consumer can hold back the other downstream consumers resulting in lowered throughput. In other words the rate of @@ -415,7 +415,7 @@ var graph = RunnableGraph.FromGraph(GraphDsl.Create(mysink1, mysink2, mysink3, T })); ``` -####Collecting missed ticks +#### Collecting missed ticks **Situation:** Given a regular (stream) source of ticks, instead of trying to backpressure the producer of the ticks we want to keep a counter of the missed ticks instead and pass it down when possible. @@ -437,7 +437,7 @@ var missed = Flow.Create() .ConflateWithSeed(seed: _ => 0, aggregate: (missedTicks, tick) => missedTicks + 1); ``` -####Create a stream processor that repeats the last element seen +#### Create a stream processor that repeats the last element seen **Situation:** Given a producer and consumer, where the rate of neither is known in advance, we want to ensure that none of them is slowing down the other by dropping earlier unconsumed elements from the upstream if necessary, and repeating @@ -553,7 +553,7 @@ public sealed class HoldWithWait : GraphStage> } ``` -####Globally limiting the rate of a set of streams +#### Globally limiting the rate of a set of streams **Situation:** Given a set of independent streams that we cannot merge, we want to globally limit the aggregate throughput of the set of streams. @@ -682,9 +682,9 @@ public Flow LimitGlobal(IActorRef limiter, TimeSpan maxAllowed > [!NOTE] > The global actor used for limiting introduces a global bottleneck. You might want to assign a dedicated dispatcher for this actor. -#Working with IO +# Working with IO -####Chunking up a stream of ByteStrings into limited size ByteStrings +#### Chunking up a stream of ByteStrings into limited size ByteStrings **Situation:** Given a stream of ByteStrings we want to produce a stream of ByteStrings containing the same bytes in the same sequence, but capping the size of ByteStrings. In other words we want to slice up ByteStrings into smaller @@ -775,7 +775,7 @@ var rawBytes = Source.Empty(); var chunkStream = rawBytes.Via(new Chunker(ChunkLimit)); ``` -####Limit the number of bytes passing through a stream of ByteStrings +#### Limit the number of bytes passing through a stream of ByteStrings **Situation:** Given a stream of ByteStrings we want to fail the stream if more than a given maximum of bytes has been consumed. @@ -827,7 +827,7 @@ public class ByteLimiter : GraphStage> var limiter = Flow.Create().Via(new ByteLimiter(SizeLimit)); ``` -####Compact ByteStrings in a stream of ByteStrings +#### Compact ByteStrings in a stream of ByteStrings **Situation:** After a long stream of transformations, due to their immutable, structural sharing nature ByteStrings may refer to multiple original ByteString instances unnecessarily retaining memory. As the final step of a transformation @@ -841,7 +841,7 @@ var data = Source.Empty(); var compacted = data.Select(b => b.Compact()); ``` -####Injecting keep-alive messages into a stream of ByteStrings +#### Injecting keep-alive messages into a stream of ByteStrings **Situation:** Given a communication channel expressed as a stream of ByteStrings we want to inject keep-alive messages but only if this does not interfere with normal traffic. diff --git a/docs/articles/streams/customstreamprocessing.md b/docs/articles/streams/custom-stream-processing.md similarity index 92% rename from docs/articles/streams/customstreamprocessing.md rename to docs/articles/streams/custom-stream-processing.md index 3c1ddf66acb..52414e2b3e6 100644 --- a/docs/articles/streams/customstreamprocessing.md +++ b/docs/articles/streams/custom-stream-processing.md @@ -1,15 +1,15 @@ --- -layout: docs.hbs +uid: custom-stream-processing title: Custom stream processing --- -#Custom stream processing +# Custom stream processing While the processing vocabulary of Akka Streams is quite rich (see the [Streams Cookbook](cookbook.md) for examples) it is sometimes necessary to define new transformation stages either because some functionality is missing from the stock operations, or for preformance reasons. In this part we show how to build custom processing stages and graph junctions of various kinds. > [!NOTE] > A custom graph stage should not be the first tool you reach for, defining graphs using flows and the graph DSL is in general easier and does to a larger extent protect you from mistakes that might be easy to make with a custom `GraphStage` -##Custom processing with GraphStage +## Custom processing with GraphStage The `GraphStage` abstraction can be used to create arbitrary graph processing stages with any number of input or output ports. It is a counterpart of the `GraphDSL.Create()` method which creates new stream processing stages by composing others. Where `GraphStage` differs is that it creates a stage that is itself not divisible into smaller ones, and allows state to be maintained inside it in a safe way. As a first motivating example, we will build a new `Source` that will simply emit numbers from 1 until it is cancelled. To start, we need to define the "interface" of our stage, which is called shape in Akka Streams terminology (this is explained in more detail in the section [Modularity, Composition and Hierarchy](modularitycomposition.md)). This is how this looks like: @@ -93,7 +93,7 @@ var result1Task = mySource.Take(10).RunAggregate(0, (sum, next) => sum + next, m var result2Task = mySource.Take(100).RunAggregate(0, (sum, next) => sum + next, materializer); ``` -###Port states, InHandler and OutHandler +### Port states, InHandler and OutHandler In order to interact with a port (`Inlet` or `Outlet`) of the stage we need to be able to receive events and generate new events belonging to the port. From the `GraphStageLogic` the following operations are available on an output port: @@ -155,7 +155,7 @@ Note that since the above methods are implemented by temporarily replacing the h An example of how this API simplifies a stage can be found below in the second version of the Duplicator. -###Custom linear processing stages using GraphStage +### Custom linear processing stages using GraphStage Graph stages allows for custom linear processing stages through letting them have one input and one output and using `FlowShape` as their shape. @@ -360,13 +360,83 @@ If we attempt to draw the sequence of events, it shows that there is one "event ![Graph stage tracks](/images/graph_stage_tracks_11.png) -###Completion +### Completion Completion handling usually (but not exclusively) comes into the picture when processing stages need to emit a few more elements after their upstream source has been completed. We have seen an example of this in our first `Duplicator` implementation where the last element needs to be doubled even after the upstream neighbour stage has been completed. This can be done by overriding the `onUpstreamFinish` callback in `SetHandler(in, action)`. Stages by default automatically stop once all of their ports (input and output) have been closed externally or internally. It is possible to opt out from this behavior by invoking `SetKeepGoing(true)` (which is not supported from the stage’s constructor and usually done in `PreStart`). In this case the stage **must** be explicitly closed by calling `CompleteStage()` or `FailStage(exception)`. This feature carries the risk of leaking streams and actors, therefore it should be used with care. -###Using timers +### Logging inside GraphStages + +Logging debug or other important information in your stages is often a very good idea, especially when developing +more advances stages which may need to be debugged at some point. + +The `Log` property is provided to enable you to easily obtain a `LoggingAdapter` +inside of a `GraphStage` as long as the `Materializer` you're using is able to provide you with a logger. +In that sense, it serves a very similar purpose as `ActorLogging` does for Actors. + +> [!NOTE] +> Please note that you can always simply use a logging library directly inside a Stage. +Make sure to use an asynchronous appender however, to not accidentally block the stage when writing to files etc. + +The stage gets access to the `Log` property which it can safely use from any ``GraphStage`` callbacks: + +```csharp +private sealed class RandomLettersSource : GraphStage> +{ + #region internal classes + + private sealed class Logic : GraphStageLogic + { + public Logic(RandomLettersSource stage) : base(stage.Shape) + { + SetHandler(stage.Out, onPull: () => + { + var c = NextChar(); // ASCII lower case letters + + Log.Debug($"Randomly generated: {c}"); + + Push(stage.Out, c.ToString()); + }); + } + + private static char NextChar() => (char) ThreadLocalRandom.Current.Next('a', 'z'1); + } + + #endregion + + public RandomLettersSource() + { + Shape = new SourceShape(Out); + } + + private Outlet Out { get; } = new Outlet("RandomLettersSource.out"); + + public override SourceShape Shape { get; } + + protected override GraphStageLogic CreateLogic(Attributes inheritedAttributes) => new Logic(this); +} + + +[Fact] +public void A_GraphStageLogic_must_support_logging_in_custom_graphstage() +{ + const int n = 10; + EventFilter.Debug(start: "Randomly generated").Expect(n, () => + { + Source.FromGraph(new RandomLettersSource()) + .Take(n) + .RunWith(Sink.Ignore(), Materializer) + .Wait(TimeSpan.FromSeconds(3)); + }); +} +``` + +> [!NOTE] +> **SPI Note:** If you're implementing a Materializer, you can add this ability to your materializer by implementing +`IMaterializerLoggingProvider` in your `Materializer`. + +### Using timers It is possible to use timers in `GraphStages` by using `TimerGraphStageLogic` as the base class for the returned logic. Timers can be scheduled by calling one of `ScheduleOnce(key,delay)`, `SchedulePeriodically(key,period)` or `SchedulePeriodicallyWithInitialDelay(key,delay,period)` and passing an object as a key for that timer (can be any object, for example a String). The `OnTimer(key)` method needs to be overridden and it will be called once the timer of key fires. It is possible to cancel a timer using `CancelTimer(key)` and check the status of a timer with `IsTimerActive(key)`. Timers will be automatically cleaned up when the stage completes. @@ -420,7 +490,7 @@ class TimedGate : GraphStage> } ``` -###Using asynchronous side-channels +### Using asynchronous side-channels In order to receive asynchronous events that are not arriving as stream elements (for example a completion of a task or a callback from a 3rd party API) one must acquire a `AsyncCallback` by calling `GetAsyncCallback()` from the stage logic. The method `GetAsyncCallback` takes as a parameter a callback that will be called once the asynchronous event fires. It is important to **not call the callback directly**, instead, the external API must `invoke` the returned `Action`. The execution engine will take care of calling the provided callback in a thread-safe way. The callback can safely access the state of the `GraphStageLogic` implementation. @@ -468,7 +538,7 @@ class KillSwitch : GraphStage> } ``` -###Integration with actors +### Integration with actors **This section is a stub and will be extended in the next release This is an experimental feature*** @@ -478,7 +548,7 @@ It is possible to acquire an ActorRef that can be addressed from the outside of * they cannot be returned as materialized values. * they cannot be accessed from the constructor of the `GraphStageLogic`, but they can be accessed from the `PreStart()` method. -###Custom materialized values +### Custom materialized values Custom stages can return materialized values instead of `NotUsed` by inheriting from `GraphStageWithMaterializedValue` instead of the simpler `GraphStage`. The difference is that in this case the method `CreateLogicAndMaterializedValue(inheritedAttributes)` needs to be overridden, and in addition to the stage logic the materialized value must be provided @@ -528,7 +598,7 @@ class FirstValue : GraphStageWithMaterializedValue, Task> } ``` -##Using attributes to affect the behavior of a stage +## Using attributes to affect the behavior of a stage **This section is a stub and will be extended in the next release** @@ -536,7 +606,7 @@ Stages can access the `Attributes` object created by the materializer. This cont See [Modularity, Composition and Hierarchy](modularitycomposition.md) for an explanation on how attributes work. -###Rate decoupled graph stages +### Rate decoupled graph stages Sometimes it is desirable to decouple the rate of the upstream and downstream of a stage, synchronizing only when needed. @@ -631,7 +701,7 @@ class TwoBuffer : GraphStage> } ``` -##Thread safety of custom processing stages +## Thread safety of custom processing stages **All of the above custom stages (linear or graph) provide a few simple guarantees that implementors can rely on.** @@ -643,7 +713,7 @@ In essence, the above guarantees are similar to what `Actor`'s provide, if one t > [!WARNING] > It is **not** safe to access the state of any custom stage outside of the callbacks that it provides, just like it is unsafe to access the state of an actor from the outside. This means that Future callbacks should not close over internal state of custom stages because such access can be concurrent with the provided callbacks, leading to undefined behavior. -##Extending Flow Combinators with Custom Operators +## Extending Flow Combinators with Custom Operators The most general way of extending any `Source`, `Flow` or `SubFlow` (e.g. from `GroupBy`) is demonstrated above: create a graph of flow-shape like the `Filter` example given above and use the `.Via(...)` combinator to integrate it into your stream topology. This works with all `IFlow` sub-types, including the ports that you connect with the graph DSL. diff --git a/docs/articles/streams/designprinciples.md b/docs/articles/streams/designprinciples.md index 1eb17457575..f5973362c21 100644 --- a/docs/articles/streams/designprinciples.md +++ b/docs/articles/streams/designprinciples.md @@ -3,13 +3,13 @@ layout: docs.hbs title: Design Principles behind Akka Streams --- -#Design Principles behind Akka Streams +# Design Principles behind Akka Streams It took quite a while until we were reasonably happy with the look and feel of the API and the architecture of the implementation, and while being guided by intuition the design phase was very much exploratory research. This section details the findings and codifies them into a set of principles that have emerged during the process. > [!NOTE] > As detailed in the introduction keep in mind that the Akka Streams API is completely decoupled from the Reactive Streams interfaces which are just an implementation detail for how to pass stream data between individual processing stages. -##What shall users of Akka Streams expect? +## What shall users of Akka Streams expect? Akka is built upon a conscious decision to offer APIs that are minimal and consistent --as opposed to easy or intuitive. The credo is that we favour explicitness over magic, and if we provide a feature then it must work always, no exceptions. Another way to say this is that we minimize the number of rules a user has to learn instead of trying to keep the rules close to what we think users might expect. From this follows that the principles implemented by Akka Streams are: @@ -20,7 +20,7 @@ From this follows that the principles implemented by Akka Streams are: This means that we provide all the tools necessary to express any stream processing topology, that we model all the essential aspects of this domain (back-pressure, buffering, transformations, failure recovery, etc.) and that whatever the user builds is reusable in a larger context. -###Akka Streams does not send dropped stream elements to the dead letter office +### Akka Streams does not send dropped stream elements to the dead letter office One important consequence of offering only features that can be relied upon is the restriction that Akka Streams cannot ensure that all objects sent through a processing topology will be processed. Elements can be dropped for a number of reason: - plan user code can consume on element in a Select(...) stage and produce an entirely different one as its result @@ -30,12 +30,12 @@ One important consequence of offering only features that can be relied upon is t This means that sending CLR objects into a stream that needs to be cleaned up will require the user to ensure that this happens outside of the Akka Streams facilities (e.g. by cleaning them up after a time-out or when their results are observed on the stream output, or by other means like finalizers etc.) -###Resulting implementation Constraints +### Resulting implementation Constraints Compositionality entails re-usability of partial stream topologies, which led us to the lifted approach of describing data flows as (partial) graphs that can act as composite sources, flows (a.k.a. pipes) and sinks of data. These building blocks shall then be freely shareable, with the ability to combine them freely to form larger graphs. The representation of these pieces must therefore be an immutable blueprint that is materialized in an explicit step in order to start the stream processing. The resulting stream processing engine is then also immutable in the sense of having a fixed topology that is prescribed by the blueprint. Dynamic networks need to be modelled by explicitly using the Reactive Streams interfaces for plugging different engines together. The process of materialization will often create specific objects that are useful to interact with the processing engine once it is running, for example for shutting it down or for extracting metrics. This means that the materialization function produces a result termed the *materialized value of a graph*. -##What shall users of streaming libraries expect? +## What shall users of streaming libraries expect? We expect libraries to be built on top of Akka Streams, in fact on the JVM" Akka HTTP is one such example that lives within the Akka project itself. In order to allow users to profit from the principles that are described for Akka Streams above, the following rules are established: - libraries shall provide their users with reusable pieces, i.e expose factories that return graphs, allowing full compositionality @@ -47,7 +47,7 @@ The second rule allows a library to additionally provide nice sugar for the comm > [!NOTE] > One important consequence of this is that a reusable flow description cannot be bound to "live" resources, any connection to or allocation of such resources must be deferred until materialization time. Examples of "live" resources are already existing TCP connections, a multicast Publisher, etc.; a TickSource does not fall into this category if its timer is created only upon materialization (as is the case for our implementation).
Exceptions from this need to be well-justified and carefully documented. -###Resulting Implementation Constraints +### Resulting Implementation Constraints Akka Streams must enable a library to express any stream processing utility in terms of immutable blueprints. The most common building blocks are - Source: something with exactly one output stream @@ -59,7 +59,7 @@ Akka Streams must enable a library to express any stream processing utility in t > [!NOTE] > A source that emits a stream of streams is still just a normal Source, the kind of elements that are produced does not play a role in the static stream topology that is being expressed. -##The difference between Error and Failure +## The difference between Error and Failure The starting point for this discussion is the definition given by the [Reactive Manifesto](http://www.reactivemanifesto.org/glossary#Failure). Translated to streams this means that an error is accessible within the stream as a normal data element, while a failure means that the stream itself has failed and is collapsing. In concrete terms, on the Reactive Streams interface level data elements (including errors) are signalled via `onNext` while failures raise the `onError` signal. > [!NOTE] @@ -69,7 +69,7 @@ There is only limited support for treating `onError` in Akka Streams compared to The ability for failures to propagate faster than data elements is essential for tearing down streams that are back-pressured --especially since back-pressure can be the failure mode (e.g. by tripping upstream buffers which then abort because they cannot do anything else; or if a dead-lock occurred). -##The semantics of stream recovery +## The semantics of stream recovery A recovery element (i.e. any transformation that absorbs an `onError` signal and turns that into possibly more data elements followed normal stream completion) acts as a bulkhead that confines a stream collapse to a given region of the stream topology. Within the collapsed region buffered elements may be lost, but the outside is not affected by the failure. This works in the same fashion as a `try-catch` expression: it marks a region in which exceptions are caught, but the exact amount of code that was skipped within this region in case of a failure might not be known precisely-the placement of statements matters. diff --git a/docs/articles/streams/error-handling.md b/docs/articles/streams/error-handling.md index 2b2e974df5e..91a58997477 100644 --- a/docs/articles/streams/error-handling.md +++ b/docs/articles/streams/error-handling.md @@ -11,7 +11,7 @@ strategies, but the semantics have been adapted to the domain of stream processi > *ZipWith*, *GraphStage* junction, *ActorPublisher* source and *ActorSubscriber* sink components do not honour the supervision strategy attribute yet. -#Supervision Strategies +# Supervision Strategies There are three ways to handle exceptions from application code: @@ -92,7 +92,7 @@ var result = source.Limit(1000).RunWith(Sink.Seq(), materializer); // result here will be a Task completed with Success(List(0, 1, 4, 0, 5, 12)) ``` -#Errors from SelectAsync +# Errors from SelectAsync Stream supervision can also be applied to the tasks of ``SelectAsync``. Let's say that we use an external service to lookup email addresses and we would like to diff --git a/docs/articles/streams/integration.md b/docs/articles/streams/integration.md index 5365a3df6f6..062bfc9d8f6 100644 --- a/docs/articles/streams/integration.md +++ b/docs/articles/streams/integration.md @@ -3,31 +3,108 @@ layout: docs.hbs title: Integration --- -#Integrating with Actors -For piping the elements of a stream as messages to an ordinary actor you can use the -``Sink.ActorRef``. Messages can be sent to a stream via the `IActorRef` that is -materialized by ``Source.ActorRef``. +# Integrating with Actors +For piping the elements of a stream as messages to an ordinary actor you can use ``Ask`` in a +``SelectAsync`` or use ``Sink.ActorRefWithAck``. -For more advanced use cases the `IActorPublisher` and `IActorSubscriber` interfaces are -provided to support implementing Reactive Streams `IPublisher` and `ISubscriber` with an `Actor`. +Messages can be sent to a stream with ``Source.Queue`` or via the ``IActorRef`` that is +materialized by ``Source.ActorRef``. -These can be consumed by other Reactive Stream libraries or used as a Akka Streams `Source` or `Sink`. +#### SelectAsync + Ask +A nice way to delegate some processing of elements in a stream to an actor is to use ``Ask`` +in ``SelectAsync``. The back-pressure of the stream is maintained by the ``Task`` of the ``Ask`` +and the mailbox of the actor will not be filled with more messages than the given +``parallelism`` of the ``SelectAsync`` stage. +```csharp +var words = Source.From(new [] { "hello", "hi" }); +words + .SelectAsync(5, elem => _actorRef.Ask(elem, TimeSpan.FromSeconds(5))) + .Select(elem => (string)elem) + .Select(elem => elem.ToLower()) + .RunWith(Sink.Ignore(), _actorMaterializer); +``` -> [!WARNING] -> `IActorPublisher` and `IActorSubscriber` cannot be used with remote actors, because if signals of the -Reactive Streams protocol (e.g. ``request``) are lost the stream may deadlock. +Note that the messages received in the actor will be in the same order as the stream elements, +i.e. the `parallelism` does not change the ordering of the messages. There is a performance +advantage of using parallelism > 1 even though the actor will only process one message at a time +because then there is already a message in the mailbox when the actor has completed previous message. -####Source.ActorRef +The actor must reply to the `Sender` for each message from the stream. That reply will complete +the `CompletionStage` of the `Ask` and it will be the element that is emitted downstreams +from `SelectAsync`. +```csharp +public class Translator : ReceiveActor +{ + public Translator() + { + Receive(word => { + // ... process message + string reply = word.ToUpper(); + // reply to the ask + Sender.Tell(reply, Self); + }); + } +} +``` +The stream can be completed with failure by sending `Akka.Actor.Status.Failure` as reply from the actor. + +If the `Ask` fails due to timeout the stream will be completed with `TimeoutException` failure. +If that is not desired outcome you can use `Recover` on the `Ask` `CompletionStage`. + +If you don't care about the replies you can use `Sink.Ignore` after the `SelectAsync` stage +and then actor is effectively a sink of the stream. + +The same pattern can be used with [Actor routers](../actors/routers.md#Routers). Then you can use +`SelectAsyncUnordered` for better efficiency if you don't care about the order of the emitted +downstream elements (the replies). + +#### Sink.ActorRefWithAck +The sink sends the elements of the stream to the given `IActorRef` that sends back back-pressure signal. +First element is always `OnInitMessage`, then stream is waiting for the given acknowledgement message +from the given actor which means that it is ready to process elements. +It also requires the given acknowledgement message after each stream element to make back-pressure work. + +If the target actor terminates the stream will be cancelled. When the stream is completed successfully +the given `OnCompleteMessage` will be sent to the destination actor. When the stream +is completed with failure a `Akka.Actor.Status.Failure` message will be sent to the destination actor. + +>**Note**
+>Using `Sink.ActorRef` or ordinary `Tell` from a `Select` or `ForEach` stage means that there is +>no back-pressure signal from the destination actor, i.e. if the actor is not consuming the messages +>fast enough the mailbox of the actor will grow, unless you use a bounded mailbox with zero +>`mailbox-push-timeout-time` or use a rate limiting stage in front. +>It's often better to use `Sink.ActorRefWithAck` or `Ask` in `SelectAsync`, though. + +#### Source.Queue +`Source.Queue` can be used for emitting elements to a stream from an actor (or from anything running +outside the stream). The elements will be buffered until the stream can process them. You can `Offer` +elements to the queue and they will be emitted to the stream if there is demand from downstream, +otherwise they will be buffered until request for demand is received. + +Use overflow strategy `Akka.Streams.OverflowStrategy.Backpressure` to avoid dropping of elements +if the buffer is full. + +`ISourceQueueWithComplete.OfferAsync` returns `Task` +which completes with `QueueOfferResult.Enqueued` if element was added to buffer or sent downstream. +It completes with `QueueOfferResult.Dropped` if element was dropped. It can also complete with +`QueueOfferResult.Failure` when stream failed or `QueueOfferResult.QueueClosed` +when downstream is completed. + +When used from an actor you typically `pipe` the result of the `Task` back to the actor +to continue processing. + +#### Source.ActorRef Messages sent to the actor that is materialized by ``Source.ActorRef`` will be emitted to the stream if there is demand from downstream, otherwise they will be buffered until request for demand is received. Depending on the defined `OverflowStrategy` it might drop elements if there is no space available in the buffer. The strategy ``OverflowStrategy.Backpressure`` is not supported -for this Source type, you should consider using ``IActorPublisher`` if you want a backpressured -actor interface. +for this Source type, i.e. elements will be dropped if the buffer is filled by sending +at a rate that is faster than the stream can consume. You should consider using ``Source.Queue`` +if you want a backpressured actor interface. The stream can be completed successfully by sending ``Akka.Actor.PoisonPill`` or ``Akka.Actor.Status.Success`` to the actor reference. @@ -38,456 +115,157 @@ actor reference. The actor will be stopped when the stream is completed, failed or cancelled from downstream, i.e. you can watch it to get notified when that happens. -####Sink.ActorRef - -The sink sends the elements of the stream to the given `IActorRef`. If the target actor terminates -the stream will be cancelled. When the stream is completed successfully the given ``OnCompleteMessage`` -will be sent to the destination actor. When the stream is completed with failure a ``Akka.Actor.Status.Failure`` -message will be sent to the destination actor. - ->**Warning**
-There is no back-pressure signal from the destination actor, i.e. if the actor is not consuming the messages fast enough -the mailbox of the actor will grow. For potentially slow consumer actors it is recommended to use a bounded mailbox -with zero `mailbox-push-timeout-time` or use a rate limiting stage in front of this stage. - -####ActorPublisher -Extend/mixin `Akka.Streams.Actor.ActorPublisher` in your `Actor` to make it a -stream publisher that keeps track of the subscription life cycle and requested elements. +# Integrating with External Services +Stream transformations and side effects involving external non-stream based services can be +performed with ``SelectAsync`` or ``SelectAsyncUnordered``. -Here is an example of such an actor. It dispatches incoming jobs to the attached subscriber: +For example, sending emails to the authors of selected tweets using an external +email service: ```csharp -public sealed class Job -{ - public Job(string payload) - { - Payload = payload; - } +Task Send(Email mail) +``` - public string Payload { get; } -} +We start with the tweet stream of authors: -public sealed class JobAccepted -{ - public static JobAccepted Instance { get; } = new JobAccepted(); +```csharp +var authors = tweets + .Where(t => t.HashTags.Contains("Akka.Net")) + .Select(t => t.Author); +``` - private JobAccepted() { } -} +Assume that we can lookup their email address using: -public sealed class JobDenied -{ - public static JobDenied Instance { get; } = new JobDenied(); +```csharp +Task LookupEmail(string handle) +``` - private JobDenied() { } -} +Transforming the stream of authors to a stream of email addresses by using the ``LookupEmail`` +service can be done with ``SelectAsync``: -public class JobManager : Actors.ActorPublisher -{ - public static Props Props { get; } = Props.Create(); - - private List _buffer; - private const int MaxBufferSize = 100; +```csharp +var emailAddresses = authors + .SelectAsync(4, author => AddressSystem.LookupEmail(author.Handle)) + .Collect(s => string.IsNullOrWhiteSpace(s) ? null : s); +``` - public JobManager() - { - _buffer = new List(); - } +Finally, sending the emails: - protected override bool Receive(object message) - { - return message.Match() - .With(job => - { - if (_buffer.Count == MaxBufferSize) - Sender.Tell(JobDenied.Instance); - else - { - Sender.Tell(JobAccepted.Instance); - if (_buffer.Count == 0 && TotalDemand > 0) - OnNext(job); - else - { - _buffer.Add(job); - DeliverBuffer(); - } - } - }) - .With(DeliverBuffer) - .With(() => Context.Stop(Self)) - .WasHandled; - } +```csharp +var sendEmails = emailAddresses.SelectAsync(4, address => + EmailServer.Send( + new Email(to: address, title: "Akka.Net", body: "I like your tweet")) + ) + .To(Sink.Ignore()); - private void DeliverBuffer() - { - if (TotalDemand > 0) - { - // totalDemand is a Long and could be larger than - // what _buffer.Take and Skip can accept - if (TotalDemand < int.MaxValue) - { - var use = _buffer.Take((int) TotalDemand).ToList(); - _buffer = _buffer.Skip((int) TotalDemand).ToList(); - use.ForEach(OnNext); - } - else - { - var use = _buffer.Take(int.MaxValue).ToList(); - _buffer = _buffer.Skip(int.MaxValue).ToList(); - use.ForEach(OnNext); - DeliverBuffer(); - } - } - } -} +sendEmails.Run(materializer); ``` -You send elements to the stream by calling ``OnNext``. You are allowed to send as many -elements as have been requested by the stream subscriber. This amount can be inquired with -``TotalDemand``. It is only allowed to use ``OnNext`` when ``IsActive`` and ``TotalDemand > 0``, -otherwise ``OnNext`` will throw ``IllegalStateException``. +``SelectAsync`` is applying the given function that is calling out to the external service to +each of the elements as they pass through this processing step. The function returns a `Task` +and the value of that task will be emitted downstreams. The number of Tasks +that shall run in parallel is given as the first argument to ``SelectAsync``. +These Tasks may complete in any order, but the elements that are emitted +downstream are in the same order as received from upstream. -When the stream subscriber requests more elements the ``ActorPublisherMessage.Request`` message -is delivered to this actor, and you can act on that event. The ``TotalDemand`` -is updated automatically. +That means that back-pressure works as expected. For example if the ``EmailServer.Send`` +is the bottleneck it will limit the rate at which incoming tweets are retrieved and +email addresses looked up. -When the stream subscriber cancels the subscription the ``ActorPublisherMessage.Cancel`` message -is delivered to this actor. After that subsequent calls to ``OnNext`` will be ignored. +The final piece of this pipeline is to generate the demand that pulls the tweet +authors information through the emailing pipeline: we attach a ``Sink.Ignore`` +which makes it all run. If our email process would return some interesting data +for further transformation then we would of course not ignore it but send that +result stream onwards for further processing or storage. -You can complete the stream by calling ``OnComplete``. After that you are not allowed to -call ``OnNext``, ``OnError`` and ``OnComplete``. +Note that ``SelectAsync`` preserves the order of the stream elements. In this example the order +is not important and then we can use the more efficient ``SelectAsyncUnordered``: -You can terminate the stream with failure by calling ``OnError``. After that you are not allowed to -call ``OnNext``, ``OnError`` and ``OnComplete``. +```csharp +var authors = tweets + .Where(t => t.HashTags.Contains("Akka.Net")) + .Select(t => t.Author); + +var emailAddresses = authors + .SelectAsyncUnordered(4, author => AddressSystem.LookupEmail(author.Handle)) + .Collect(s => string.IsNullOrWhiteSpace(s) ? null : s); + +var sendEmails = emailAddresses.SelectAsyncUnordered(4, address => + EmailServer.Send( + new Email(to: address, title: "Akka.Net", body: "I like your tweet")) + ) + .To(Sink.Ignore()); -If you suspect that this ``ActorPublisher`` may never get subscribed to, you can set the ``SubscriptionTimeout`` -property to provide a timeout after which this Publisher should be considered canceled. The actor will be notified when -the timeout triggers via an ``ActorPublisherMessage.SubscriptionTimeoutExceeded`` message and MUST then perform -cleanup and stop itself. +sendEmails.Run(materializer); +``` -If the actor is stopped the stream will be completed, unless it was not already terminated with -failure, completed or canceled. +In the above example the services conveniently returned a `Task` of the result. +If that is not the case you need to wrap the call in a `Task`. -More detailed information can be found in the API documentation. -This is how it can be used as input `Source` to a `Flow`: +For a service that is exposed as an actor, or if an actor is used as a gateway in front of an +external service, you can use ``Ask``: ```csharp -var jobManagerSource = Source.ActorPublisher(JobManager.Props); -var actorRef = Flow.Create() - .Select(x => x.Payload.ToUpper()) - .Select(x => - { - Console.WriteLine(x); - return x; - }) - .To(Sink.Ignore()) - .RunWith(jobManagerSource, materializer); +var akkaTweets = tweets.Where(t => t.HashTags.Contains("Akka.Net")); -actorRef.Tell(new Job("a")); -actorRef.Tell(new Job("b")); -actorRef.Tell(new Job("c")); +var saveTweets = akkaTweets + .SelectAsync(4, tweet => database.Ask(new Save(tweet), TimeSpan.FromSeconds(3))) + .To(Sink.Ignore()); ``` -A publisher that is created with ``Sink.AsPublisher`` supports a specified number of subscribers. Additional -subscription attempts will be rejected with an `IllegalStateException`. +Note that if the ``Ask`` is not completed within the given timeout the stream is completed with failure. +If that is not desired outcome you can use ``Recover`` on the ``Ask`` `Task`. -####ActorSubscriber -Extend/mixin `Akka.Stream.Actor.ActorSubscriber` in your `Actor` to make it a -stream subscriber with full control of stream back pressure. It will receive -``ActorSubscriberMessage.OnNext``, ``ActorSubscriberMessage.OnComplete`` and ``ActorSubscriberMessage.OnError`` -messages from the stream. It can also receive other, non-stream messages, in the same way as any actor. -Here is an example of such an actor. It dispatches incoming jobs to child worker actors: +#### Illustrating ordering and parallelism +Let us look at another example to get a better understanding of the ordering +and parallelism characteristics of ``SelectAsync`` and ``SelectAsyncUnordered``. -```csharp -public class Message -{ - public int Id { get; } +Several ``SelectAsync`` and ``SelectAsyncUnordered`` tasks may run concurrently. +The number of concurrent tasks are limited by the downstream demand. +For example, if 5 elements have been requested by downstream there will be at most 5 +tasks in progress. - public IActorRef ReplyTo { get; } +``SelectAsync`` emits the task results in the same order as the input elements +were received. That means that completed results are only emitted downstream +when earlier results have been completed and emitted. One slow call will thereby +delay the results of all successive calls, even though they are completed before +the slow call. - public Message(int id, IActorRef replyTo) - { - Id = id; - ReplyTo = replyTo; - } -} +``SelectAsyncUnordered`` emits the task results as soon as they are completed, i.e. +it is possible that the elements are not emitted downstream in the same order as +received from upstream. One slow call will thereby not delay the results of faster +successive calls as long as there is downstream demand of several elements. -public class Work +Here is a fictive service that we can use to illustrate these aspects. + +```csharp +public class SometimesSlowService { - public Work(int id) + private readonly AtomicCounter runningCount = new AtomicCounter(); + + public Task Convert(string s) { - Id = id; + Console.WriteLine($"running {s} {runningCount.IncrementAndGet()}"); + + return Task.Run(() => + { + if(s != "" && char.IsLower(s[0])) + Thread.Sleep(500); + else + Thread.Sleep(20); + Console.WriteLine($"completed {s} {runningCount.GetAndDecrement()}"); + + return s.ToUpper(); + }); } - - public int Id { get; } } +``` -public class Reply -{ - public Reply(int id) - { - Id = id; - } +Elements starting with a lower case character are simulated to take longer time to process. - public int Id { get; } -} - -public class Done -{ - public Done(int id) - { - Id = id; - } - - public int Id { get; } -} - -public class WorkerPool : Actors.ActorSubscriber -{ - public static Props Props { get; } = Props.Create(); - - private class Strategy : MaxInFlightRequestStrategy - { - private readonly Dictionary _queue; - - public Strategy(int max, Dictionary queue) : base(max) - { - _queue = queue; - } - - public override int InFlight => _queue.Count; - } - - private const int MaxQueueSize = 10; - private readonly Dictionary _queue; - private readonly Router _router; - - public WorkerPool() - { - _queue = new Dictionary(); - var routees = new Routee[] - { - new ActorRefRoutee(Context.ActorOf()), - new ActorRefRoutee(Context.ActorOf()), - new ActorRefRoutee(Context.ActorOf()) - }; - _router = new Router(new RoundRobinRoutingLogic(), routees); - RequestStrategy = new Strategy(MaxQueueSize, _queue); - } - - public override IRequestStrategy RequestStrategy { get; } - - protected override bool Receive(object message) - { - return message.Match() - .With(next => - { - var msg = next.Element as Message; - if (msg != null) - { - _queue.Add(msg.Id, msg.ReplyTo); - if (_queue.Count <= MaxQueueSize) - throw new IllegalStateException($"Queued too many : {_queue.Count}"); - _router.Route(new Work(msg.Id), Self); - } - }) - .With(reply => - { - _queue[reply.Id].Tell(new Done(reply.Id)); - _queue.Remove(reply.Id); - }) - .WasHandled; - } -} - -public class Worker : ReceiveActor -{ - public Worker() - { - Receive(work => - { - //... - Sender.Tell(new Reply(work.Id)); - }); - } -} -``` - -Subclass must define the ``RequestStrategy`` to control stream back pressure. -After each incoming message the ``ActorSubscriber`` will automatically invoke -the ``RequestStrategy.RequestDemand`` and propagate the returned demand to the stream. - -* The provided ``WatermarkRequestStrategy`` is a good strategy if the actor performs work itself. -* The provided ``MaxInFlightRequestStrategy`` is useful if messages are queued internally or - delegated to other actors. -* You can also implement a custom ``RequestStrategy`` or call ``Request`` manually together with - ``ZeroRequestStrategy`` or some other strategy. In that case - you must also call ``Request`` when the actor is started or when it is ready, otherwise - it will not receive any elements. - -More detailed information can be found in the API documentation. - -This is how it can be used as output `Sink` to a `Flow`: - -```csharp -var n = 118; -Source.From(Enumerable.Range(1, n)) - .Select(x => new Message(x, replyTo)) - .RunWith(Sink.ActorSubscriber(WorkerPool.Props), materializer); -``` - -#Integrating with External Services -Stream transformations and side effects involving external non-stream based services can be -performed with ``SelectAsync`` or ``SelectAsyncUnordered``. - -For example, sending emails to the authors of selected tweets using an external -email service: - -```csharp -Task Send(Email mail) -``` - -We start with the tweet stream of authors: - -```csharp -var authors = tweets - .Where(t => t.HashTags.Contains("Akka.Net")) - .Select(t => t.Author); -``` - -Assume that we can lookup their email address using: - -```csharp -Task LookupEmail(string handle) -``` - -Transforming the stream of authors to a stream of email addresses by using the ``LookupEmail`` -service can be done with ``SelectAsync``: - -```csharp -var emailAddresses = authors - .SelectAsync(4, author => AddressSystem.LookupEmail(author.Handle)) - .Collect(s => string.IsNullOrWhiteSpace(s) ? null : s); -``` - -Finally, sending the emails: - -```csharp -var sendEmails = emailAddresses.SelectAsync(4, address => - EmailServer.Send( - new Email(to: address, title: "Akka.Net", body: "I like your tweet")) - ) - .To(Sink.Ignore()); - -sendEmails.Run(materializer); -``` - -``SelectAsync`` is applying the given function that is calling out to the external service to -each of the elements as they pass through this processing step. The function returns a `Task` -and the value of that task will be emitted downstreams. The number of Tasks -that shall run in parallel is given as the first argument to ``SelectAsync``. -These Tasks may complete in any order, but the elements that are emitted -downstream are in the same order as received from upstream. - -That means that back-pressure works as expected. For example if the ``EmailServer.Send`` -is the bottleneck it will limit the rate at which incoming tweets are retrieved and -email addresses looked up. - -The final piece of this pipeline is to generate the demand that pulls the tweet -authors information through the emailing pipeline: we attach a ``Sink.Ignore`` -which makes it all run. If our email process would return some interesting data -for further transformation then we would of course not ignore it but send that -result stream onwards for further processing or storage. - -Note that ``SelectAsync`` preserves the order of the stream elements. In this example the order -is not important and then we can use the more efficient ``SelectAsyncUnordered``: - -```csharp -var authors = tweets - .Where(t => t.HashTags.Contains("Akka.Net")) - .Select(t => t.Author); - -var emailAddresses = authors - .SelectAsyncUnordered(4, author => AddressSystem.LookupEmail(author.Handle)) - .Collect(s => string.IsNullOrWhiteSpace(s) ? null : s); - -var sendEmails = emailAddresses.SelectAsyncUnordered(4, address => - EmailServer.Send( - new Email(to: address, title: "Akka.Net", body: "I like your tweet")) - ) - .To(Sink.Ignore()); - -sendEmails.Run(materializer); -``` - -In the above example the services conveniently returned a `Task` of the result. -If that is not the case you need to wrap the call in a `Task`. - - -For a service that is exposed as an actor, or if an actor is used as a gateway in front of an -external service, you can use ``Ask``: - -```csharp -var akkaTweets = tweets.Where(t => t.HashTags.Contains("Akka.Net")); - -var saveTweets = akkaTweets - .SelectAsync(4, tweet => database.Ask(new Save(tweet), TimeSpan.FromSeconds(3))) - .To(Sink.Ignore()); -``` - -Note that if the ``Ask`` is not completed within the given timeout the stream is completed with failure. -If that is not desired outcome you can use ``Recover`` on the ``Ask`` `Task`. - - -####Illustrating ordering and parallelism -Let us look at another example to get a better understanding of the ordering -and parallelism characteristics of ``SelectAsync`` and ``SelectAsyncUnordered``. - -Several ``SelectAsync`` and ``SelectAsyncUnordered`` tasks may run concurrently. -The number of concurrent tasks are limited by the downstream demand. -For example, if 5 elements have been requested by downstream there will be at most 5 -tasks in progress. - -``SelectAsync`` emits the task results in the same order as the input elements -were received. That means that completed results are only emitted downstream -when earlier results have been completed and emitted. One slow call will thereby -delay the results of all successive calls, even though they are completed before -the slow call. - -``SelectAsyncUnordered`` emits the task results as soon as they are completed, i.e. -it is possible that the elements are not emitted downstream in the same order as -received from upstream. One slow call will thereby not delay the results of faster -successive calls as long as there is downstream demand of several elements. - -Here is a fictive service that we can use to illustrate these aspects. - -```csharp -public class SometimesSlowService -{ - private readonly AtomicCounter runningCount = new AtomicCounter(); - - public Task Convert(string s) - { - Console.WriteLine($"running {s} {runningCount.IncrementAndGet()}"); - - return Task.Run(() => - { - if(s != "" && char.IsLower(s[0])) - Thread.Sleep(500); - else - Thread.Sleep(20); - Console.WriteLine($"completed {s} {runningCount.GetAndDecrement()}"); - - return s.ToUpper(); - }); - } -} -``` - -Elements starting with a lower case character are simulated to take longer time to process. - -Here is how we can use it with ``SelectAsync``: +Here is how we can use it with ``SelectAsync``: ```csharp @@ -626,7 +404,7 @@ The numbers in parenthesis illustrates how many calls that are in progress at the same time. Here the downstream demand and thereby the number of concurrent calls are limited by the buffer size (4) of the `ActorMaterializerSettings`. -####Integrating with Reactive Streams +#### Integrating with Reactive Streams `Reactive Streams` defines a standard for asynchronous stream processing with non-blocking back pressure. It makes it possible to plug together stream libraries that adhere to the standard. Akka Streams is one such library. @@ -735,3 +513,306 @@ var flow = Flow.FromProcessor(()=> createProcessor(materializer)); ``` Please note that a factory is necessary to achieve reusability of the resulting `Flow`. + +#### Implementing Reactive Streams Publisher or Subscriber + +As described above any Akka Streams ``Source`` can be exposed as a Reactive Streams ``Publisher`` +and any ``Sink`` can be exposed as a Reactive Streams ``Subscriber``. Therefore we recommend that you +implement Reactive Streams integrations with built-in stages or [custom stages](customstreamprocessing.md). + +For historical reasons the `ActorPublisher` and `ActorSubscriber` are +provided to support implementing Reactive Streams `Publisher` class and `Subscriber` class with +an `Actor` class. + +These can be consumed by other Reactive Stream libraries or used as an Akka Streams `Source` class or `Sink` class. + +>**Warning**
+>`ActorPublisher` class and `ActorSubscriber` class will probably be deprecated in +>future versions of Akka. + +>**Warning**
+>`ActorPublisher` class and `ActorSubscriber` class cannot be used with remote actors, +>because if signals of the Reactive Streams protocol (e.g. ``Request``) are lost the +>the stream may deadlock. + +#### ActorPublisher +Extend `Akka.Streams.Actor.ActorPublisher` to implement a stream publisher that keeps track of the subscription life cycle and requested elements. + +Here is an example of such an actor. It dispatches incoming jobs to the attached subscriber: + +```csharp +public sealed class Job +{ + public Job(string payload) + { + Payload = payload; + } + + public string Payload { get; } +} + +public sealed class JobAccepted +{ + public static JobAccepted Instance { get; } = new JobAccepted(); + + private JobAccepted() { } +} + +public sealed class JobDenied +{ + public static JobDenied Instance { get; } = new JobDenied(); + + private JobDenied() { } +} + +public class JobManager : Actors.ActorPublisher +{ + public static Props Props { get; } = Props.Create(); + + private List _buffer; + private const int MaxBufferSize = 100; + + public JobManager() + { + _buffer = new List(); + } + + protected override bool Receive(object message) + { + return message.Match() + .With(job => + { + if (_buffer.Count == MaxBufferSize) + Sender.Tell(JobDenied.Instance); + else + { + Sender.Tell(JobAccepted.Instance); + if (_buffer.Count == 0 && TotalDemand > 0) + OnNext(job); + else + { + _buffer.Add(job); + DeliverBuffer(); + } + } + }) + .With(DeliverBuffer) + .With(() => Context.Stop(Self)) + .WasHandled; + } + + private void DeliverBuffer() + { + if (TotalDemand > 0) + { + // totalDemand is a Long and could be larger than + // what _buffer.Take and Skip can accept + if (TotalDemand < int.MaxValue) + { + var use = _buffer.Take((int) TotalDemand).ToList(); + _buffer = _buffer.Skip((int) TotalDemand).ToList(); + use.ForEach(OnNext); + } + else + { + var use = _buffer.Take(int.MaxValue).ToList(); + _buffer = _buffer.Skip(int.MaxValue).ToList(); + use.ForEach(OnNext); + DeliverBuffer(); + } + } + } +} +``` + +You send elements to the stream by calling ``OnNext``. You are allowed to send as many +elements as have been requested by the stream subscriber. This amount can be inquired with +``TotalDemand``. It is only allowed to use ``OnNext`` when ``IsActive`` and ``TotalDemand > 0``, +otherwise ``OnNext`` will throw ``IllegalStateException``. + +When the stream subscriber requests more elements the ``ActorPublisherMessage.Request`` message +is delivered to this actor, and you can act on that event. The ``TotalDemand`` +is updated automatically. + +When the stream subscriber cancels the subscription the ``ActorPublisherMessage.Cancel`` message +is delivered to this actor. After that subsequent calls to ``OnNext`` will be ignored. + +You can complete the stream by calling ``OnComplete``. After that you are not allowed to +call ``OnNext``, ``OnError`` and ``OnComplete``. + +You can terminate the stream with failure by calling ``OnError``. After that you are not allowed to +call ``OnNext``, ``OnError`` and ``OnComplete``. + +If you suspect that this ``ActorPublisher`` may never get subscribed to, you can set the ``SubscriptionTimeout`` +property to provide a timeout after which this Publisher should be considered canceled. The actor will be notified when +the timeout triggers via an ``ActorPublisherMessage.SubscriptionTimeoutExceeded`` message and MUST then perform +cleanup and stop itself. + +If the actor is stopped the stream will be completed, unless it was not already terminated with +failure, completed or canceled. + +More detailed information can be found in the API documentation. + +This is how it can be used as input `Source` to a `Flow`: + +```csharp +var jobManagerSource = Source.ActorPublisher(JobManager.Props); +var actorRef = Flow.Create() + .Select(job => job.Payload.ToUpper()) + .Select(elem => + { + Console.WriteLine(elem); + return elem; + }) + .To(Sink.Ignore()) + .RunWith(jobManagerSource, materializer); + +actorRef.Tell(new Job("a")); +actorRef.Tell(new Job("b")); +actorRef.Tell(new Job("c")); +``` + +You can only attach one subscriber to this publisher. Use a ``Broadcast``-element or attach a ``Sink.AsPublisher(true)`` to enable multiple subscribers. + +#### ActorSubscriber +Extend `Akka.Streams.Actor.ActorSubscriber` to make your class a stream subscriber with full control of stream back pressure. It will receive `OnNext`, `OnComplete` and `OnError` messages from the stream. It can also receive other, non-stream messages, in the same way as any actor. + +Here is an example of such an actor. It dispatches incoming jobs to child worker actors: + +```csharp +public class Message +{ + public int Id { get; } + + public IActorRef ReplyTo { get; } + + public Message(int id, IActorRef replyTo) + { + Id = id; + ReplyTo = replyTo; + } +} + +public class Work +{ + public Work(int id) + { + Id = id; + } + + public int Id { get; } +} + +public class Reply +{ + public Reply(int id) + { + Id = id; + } + + public int Id { get; } +} + +public class Done +{ + public Done(int id) + { + Id = id; + } + + public int Id { get; } +} + +public class WorkerPool : Actors.ActorSubscriber +{ + public static Props Props { get; } = Props.Create(); + + private class Strategy : MaxInFlightRequestStrategy + { + private readonly Dictionary _queue; + + public Strategy(int max, Dictionary queue) : base(max) + { + _queue = queue; + } + + public override int InFlight => _queue.Count; + } + + private const int MaxQueueSize = 10; + private readonly Dictionary _queue; + private readonly Router _router; + + public WorkerPool() + { + _queue = new Dictionary(); + var routees = new Routee[] + { + new ActorRefRoutee(Context.ActorOf()), + new ActorRefRoutee(Context.ActorOf()), + new ActorRefRoutee(Context.ActorOf()) + }; + _router = new Router(new RoundRobinRoutingLogic(), routees); + RequestStrategy = new Strategy(MaxQueueSize, _queue); + } + + public override IRequestStrategy RequestStrategy { get; } + + protected override bool Receive(object message) + { + return message.Match() + .With(next => + { + var msg = next.Element as Message; + if (msg != null) + { + _queue.Add(msg.Id, msg.ReplyTo); + if (_queue.Count > MaxQueueSize) + throw new IllegalStateException($"Queued too many : {_queue.Count}"); + _router.Route(new Work(msg.Id), Self); + } + }) + .With(reply => + { + _queue[reply.Id].Tell(new Done(reply.Id)); + _queue.Remove(reply.Id); + }) + .WasHandled; + } +} + +public class Worker : ReceiveActor +{ + public Worker() + { + Receive(work => + { + //... + Sender.Tell(new Reply(work.Id)); + }); + } +} +``` + +Subclass must define the ``RequestStrategy`` to control stream back pressure. +After each incoming message the ``ActorSubscriber`` will automatically invoke +the ``IRequestStrategy.RequestDemand`` and propagate the returned demand to the stream. + +* The provided ``WatermarkRequestStrategy`` is a good strategy if the actor performs work itself. +* The provided ``MaxInFlightRequestStrategy`` is useful if messages are queued internally or + delegated to other actors. +* You can also implement a custom ``IRequestStrategy`` or call ``Request`` manually together with + ``ZeroRequestStrategy`` or some other strategy. In that case + you must also call ``Request`` when the actor is started or when it is ready, otherwise + it will not receive any elements. + +More detailed information can be found in the API documentation. + +This is how it can be used as output `Sink` to a `Flow`: + +```csharp +var n = 118; +Source.From(Enumerable.Range(1, n)) + .Select(x => new Message(x, replyTo)) + .RunWith(Sink.ActorSubscriber(WorkerPool.Props), materializer); +``` \ No newline at end of file diff --git a/docs/articles/streams/introduction.md b/docs/articles/streams/introduction.md index 8bd88bf7e06..3281db9c6ce 100644 --- a/docs/articles/streams/introduction.md +++ b/docs/articles/streams/introduction.md @@ -3,9 +3,9 @@ layout: docs.hbs title: Streams Introduction --- -#Introduction +# Introduction -##Motivation +## Motivation The way we consume services from the internet today includes many instances of streaming data, both downloading from a service as well as uploading to it or peer-to-peer data transfers. Regarding data as a stream of elements instead of in its entirety is very useful because it matches the way computers send and receive them (for example via TCP), but it is often also a necessity because data sets frequently become to large to be handled as a whole. We spread computations or analyses over large clusters and call it "big data", where the whole principle of processing them is by feeding those data sequentially --as a stream-- through some CPUs. Actors can be seen as dealing with streams as well: they send and receive series of messages in order to transfer knowledge (or data) from one place to another. We have found it tedious and error-prone to implement all the proper measures in order to achieve stable streaming between actors, since in addition to sending and receiving we also need to take care to not overflow any buffers or mailboxes in the process. Another pitfall is that Actor messages can be lost and must be retransmitted in that case lest the stream have holes on the receiving side. When dealing with streams of elements of a fixed given type, Actors also do not currently offer good static guarantees that no wiring errors are made: type-safety could be improved in this case. @@ -13,12 +13,12 @@ Actors can be seen as dealing with streams as well: they send and receive series For these reasons it was decided to bundle up a solution to these problems as an Akka Streams API. The purpose is to offer an intuitive and safe way to formulate stream processing setups such that we can then execute them efficiently and with bounded resource usage -- no more OutOfMemoryErrors. In order to achieve this our streams need to be able to limit the buffering that they employ, they need to be able to slow down producers if the consumers cannot keep up. This feature is called back-pressure and is at the core of the [Reactive Streams](http://www.reactive-streams.org/) initiative of which Akka is a founding member. For you this means that the hard problem of propagating and reacting to back-pressure has been incorporated in the design of Akka Streams already, so you have one less thing to worry about; it also means that Akka Streams interoperate seamlessly with all other Reactive Streams implementations (where Reactive Streams interfaces define the interoperability SPI while implementations like Akka Streams offer a nice user API). Note that work is currently underway to provide an official reactive-streams implementation for the CLR. -##Relationship with Reactive Streams +## Relationship with Reactive Streams The Akka Streams API is completely decoupled from the Reactive Streams interfaces. While Akka Streams focus on the formulation of transformations on data streams the scope of Reactive Streams is just to define a common mechanism of how to move data across an asynchronous boundary without losses, buffering or resource exhaustion. The relationship between these two is that the Akka Streams API is geared towards end-users while the Akka Streams implementation uses the Reactive Streams interfaces internally to pass data between the different processing stages. For this reason you will not find any resemblance between the Reactive Streams interfaces and the Akka Streams API. This is in line with the expectations of the Reactive Streams project, whose primary purpose is to define interfaces such that different streaming implementation can interoperate; it is not the purpose of Reactive Streams to describe an end-user API. -##How to read these docs +## How to read these docs Stream processing is a different paradigm to the Actor Model or to Task composition, therefore it may take some careful study of this subject until you feel familiair with the tools and techniques. The documentation is here to help and for best results we recommend the following approach: * Read the [Quick Start Guide](quickstart.md) to get a feel for how streams look like and what they can do. diff --git a/docs/articles/streams/modularitycomposition.md b/docs/articles/streams/modularitycomposition.md index 3ef30a785c0..c75205a08a2 100644 --- a/docs/articles/streams/modularitycomposition.md +++ b/docs/articles/streams/modularitycomposition.md @@ -5,7 +5,7 @@ title: Modularity, Composition and Hierarchy Akka Streams provide a uniform model of stream processing graphs, which allows flexible composition of reusable components. In this chapter we show how these look like from the conceptual and API perspective, demonstrating the modularity aspects of the library. -#Basics of composition and modularity +# Basics of composition and modularity Every processing stage used in Akka Streams can be imagined as a "box" with input and output ports where elements to be processed arrive and leave the stage. In this view, a `Source` is nothing else than a "box" with a single output port, or, a `BidiFlow` is a "box" with exactly two input and two output ports. In the figure below we illustrate the most common used stages viewed as "boxes". @@ -105,7 +105,7 @@ var runnableGraph = nestedSource.To(nestedSink); var runnableGraph2 = Source.Single(0).To(Sink.Aggregate(0, (sum, x) => sum + x)); ``` -#Composing complex systems +# Composing complex systems In the previous section we explored the possibility of composition, and hierarchy, but we stayed away from non-linear, generalized graph components. There is nothing in Akka Streams though that enforces that stream processing layouts can only be linear. The DSL for `Source` and friends is optimized for creating such linear chains, as they are @@ -277,7 +277,7 @@ We have also seen, that every module has a `Shape` (for example a `Sink` has a ` independently which DSL was used to create it. This uniform representation enables the rich composability of various stream processing entities in a convenient way. -#Materialized values +# Materialized values After realizing that `RunnableGraph` is nothing more than a module with no unused ports (it is an island), it becomes clear that after materialization the only way to communicate with the running stream processing logic is via some side-channel. This side channel is represented as a *materialized value*. The situation is similar to `Actor`'s, where the @@ -375,7 +375,7 @@ var runnableGraph = nestedSource.ToMaterialized(nestedSink, (completion, rest) = > [!NOTE] > The nested structure in the above example is not necessary for combining the materialized values, it just demonstrates how the two features work together. See [Combining materialized values](basics.md#combining-materialized-values) for further examples of combining materialized values without nesting and hierarchy involved. -#Attributes +# Attributes We have seen that we can use ``Named()`` to introduce a nesting level in the fluid DSL (and also explicit nesting by using ``Create()`` from :class:`GraphDSL`). Apart from having the effect of adding a nesting level, ``Named()`` is actually a shorthand for calling ``WithAttributes(Attributes.CreateName("someName"))``. Attributes provide a way to fine-tune certain diff --git a/docs/articles/streams/pipeliningandparallelism.md b/docs/articles/streams/pipeliningandparallelism.md index d33c61690ef..6cb51925311 100644 --- a/docs/articles/streams/pipeliningandparallelism.md +++ b/docs/articles/streams/pipeliningandparallelism.md @@ -17,7 +17,7 @@ like to make pancakes, but they need to produce sufficient amount in a cooking s happy. To increase their pancake production throughput they use two frying pans. How they organize their pancake processing is markedly different. -#Pipelining +# Pipelining Bartosz uses the two frying pans in an asymmetric fashion. The first pan is only used to fry one side of the pancake then the half-finished pancake is flipped into the second pan for the finishing fry on the other side. @@ -57,7 +57,7 @@ not be able to operate at full capacity [*1](_). For more details about the behavior of these and how to add additional buffers refer to [Buffers and working with rate](buffersandworkingwithrate.md). -#Parallel processing +# Parallel processing Chris uses the two frying pans symmetrically. He uses both pans to fully fry a pancake on both sides, then puts the results on a shared plate. Whenever a pan becomes empty, he takes the next scoop from the shared bowl of batter. In essence he parallelizes the same process over multiple pans. This is how this setup will look like if implemented @@ -93,7 +93,7 @@ by strict round-robin balancing and merging stages that put in and take out panc A more detailed example of creating a worker pool can be found in the cookbook: [Balancing jobs to a fixed pool of workers](cookbook.md#balancing-jobs-to-a-fixed-pool-of-workers) -#Combining pipelining and parallel processing +# Combining pipelining and parallel processing The two concurrency patterns that we demonstrated as means to increase throughput are not exclusive. In fact, it is rather simple to combine the two approaches and streams provide diff --git a/docs/articles/streams/quickstart.md b/docs/articles/streams/quickstart.md index dc7580cbead..ac03a157a20 100644 --- a/docs/articles/streams/quickstart.md +++ b/docs/articles/streams/quickstart.md @@ -57,7 +57,7 @@ We can use the new and shiny Sink we just created by attaching it to our factori factorials.Select(_ => _.ToString()).RunWith(LineSink("factorial2.txt"), materializer); ``` -##Time-Based Processing +## Time-Based Processing Before we start looking at a more involved example we explore the streaming nature of what Akka Streams can do. Starting from the `factorials` source we transform the stream by zipping it together with another stream, represented by a `Source` that emits the number 0 to 100: the first number emitted by the `factorials` source is the factorial of zero, the second is the factorial of one, and so on. We combine these two by forming strings like "3! = 6". ```csharp diff --git a/docs/articles/streams/reactivetweets.md b/docs/articles/streams/reactivetweets.md index be64cb81657..9e1dfb55e8f 100644 --- a/docs/articles/streams/reactivetweets.md +++ b/docs/articles/streams/reactivetweets.md @@ -154,7 +154,7 @@ expresses a graph that is a *partial graph*. Concepts around composing and nesti explained in detail in [Modularity, Composition and Hierarchy](modularitycomposition.md#basics-of-composition-and-modularity). It is also possible to wrap complex computation graphs as Flows, Sinks or Sources, which will be explained in detail in [Constructing Sources, Sinks and Flows from Partial Graphs](workingwithgraphs.md#constructing-sources-sinks-and-flows-from-partial-graphs). -#Back-pressure in action +# Back-pressure in action One of the main advantages of Akka Streams is that they *always* propagate back-pressure information from stream Sinks (Subscribers) to their Sources (Publishers). It is not an optional feature, and is enabled at all times. To learn more @@ -178,7 +178,7 @@ The ``Buffer`` element takes an explicit and required ``OverflowStrategy``, whic when it receives another element while it is full. Strategies provided include dropping the oldest element (``DropHead``), dropping the entire buffer, signalling errors etc. Be sure to pick and choose the strategy that fits your use case best. -#Materialized value +# Materialized value So far we've been only processing data using Flows and consuming it into some kind of external Sink - be it by printing values or storing them in some external system. However sometimes we may be interested in some value that can be diff --git a/docs/articles/streams/stream-dynamic.md b/docs/articles/streams/stream-dynamic.md index 1ca18bb6008..4fe7b5ec2c5 100644 --- a/docs/articles/streams/stream-dynamic.md +++ b/docs/articles/streams/stream-dynamic.md @@ -3,7 +3,7 @@ layout: docs.hbs title: Dynamic stream handling --- -#Controlling graph completion with KillSwitch +# Controlling graph completion with KillSwitch A ``KillSwitch`` allows the completion of graphs of ``FlowShape`` from the outside. It consists of a flow element that can be linked to a graph of ``FlowShape`` needing completion control. @@ -32,7 +32,7 @@ Graph completion is performed by both A ``KillSwitch`` can control the completion of one or multiple streams, and therefore comes in two different flavours. -####UniqueKillSwitch +#### UniqueKillSwitch ``UniqueKillSwitch`` allows to control the completion of **one** materialized ``Graph`` of ``FlowShape``. Refer to the below for usage examples. @@ -81,7 +81,7 @@ last.Wait(); last.Exception.Should().Be(error); ``` -####SharedKillSwitch +#### SharedKillSwitch A ``SharedKillSwitch`` allows to control the completion of an arbitrary number graphs of ``FlowShape``. It can be materialized multiple times via its ``Flow`` method, and all materialized graphs linked to it are controlled by the switch. diff --git a/docs/articles/streams/testingstreams.md b/docs/articles/streams/testingstreams.md index e5c5a2246a0..d9e340cc296 100644 --- a/docs/articles/streams/testingstreams.md +++ b/docs/articles/streams/testingstreams.md @@ -16,7 +16,7 @@ flows and sinks. This makes them easily testable by wiring them up to other sources or sinks, or some test harnesses that `Akka.Testkit` or `Akka.Streams.Testkit` provide. -#Built in sources, sinks and combinators +# Built in sources, sinks and combinators Testing a custom sink can be as simple as attaching a source that emits elements from a predefined collection, running a constructed test flow and @@ -65,7 +65,7 @@ task.Wait(TimeSpan.FromMilliseconds(500)).Should().BeTrue(); task.Result.ShouldAllBeEquivalentTo(Enumerable.Range(1, 4)); ``` -#TestKit +# TestKit Akka Stream offers integration with Actors out of the box. This support can be used for writing stream tests that use familiar `TestProbe` from the @@ -132,7 +132,7 @@ task.Wait(TimeSpan.FromMilliseconds(500)).Should().BeTrue(); task.Result.Should().Be("123"); ``` -#Streams TestKit +# Streams TestKit You may have noticed various code patterns that emerge when testing stream pipelines. Akka Stream has a separate `Akka.Streams.Testkit` module that @@ -213,7 +213,7 @@ var ex = sub.ExpectError(); ex.Message.Should().Contain("C-47"); ``` -#Fuzzing Mode +# Fuzzing Mode For testing, it is possible to enable a special stream execution mode that exercises concurrent execution paths more aggressively (at the cost of reduced performance) and therefore helps exposing race conditions in tests. To diff --git a/docs/articles/streams/workingwithgraphs.md b/docs/articles/streams/workingwithgraphs.md index fe0dcb3f1fc..a00efaa9d50 100644 --- a/docs/articles/streams/workingwithgraphs.md +++ b/docs/articles/streams/workingwithgraphs.md @@ -14,7 +14,7 @@ Some graph operations which are common enough and fit the linear style of Flows, streams, such that the second one is consumed after the first one has completed), may have shorthand methods defined on `Flow` or `Source` themselves, however you should keep in mind that those are also implemented as graph junctions. -#Constructing Graphs +# Constructing Graphs Graphs are built from simple Flows which serve as the linear connections within the graphs as well as junctions which serve as fan-in and fan-out points for Flows. Thanks to the junctions having meaningful types based on their behaviour @@ -108,7 +108,7 @@ RunnableGraph.FromGraph(GraphDsl.Create(topHeadSink, bottomHeadSink, Keep.Both, })); ``` -#Constructing and combining Partial Graphs +# Constructing and combining Partial Graphs Sometimes it is not possible (or needed) to construct the entire computation graph in one place, but instead construct all of its different phases in different places and in the end connect them all into a complete graph and run it. @@ -166,7 +166,7 @@ Then we import it (all of its nodes and connections) explicitly into the closed > Please note that `GraphDSL` is not able to provide compile time type-safety about whether or not all elements have been properly connected—this validation is performed as a runtime check during the graph's instantiation. A partial graph also verifies that all ports are either connected or part of the returned `Shape`. -#Constructing Sources, Sinks and Flows from Partial Graphs +# Constructing Sources, Sinks and Flows from Partial Graphs Instead of treating a partial graph as simply a collection of flows and junctions which may not yet all be connected it is sometimes useful to expose such a complex graph as a simpler structure, @@ -229,7 +229,7 @@ var pairUpWithToString = Flow.FromGraph( pairUpWithToString.RunWith(Source.From(new[] {1}), Sink.First>(), materializer); ``` -#Combining Sources and Sinks with simplified API +# Combining Sources and Sinks with simplified API There is a simplified API you can use to combine sources and sinks with junctions like: ``Broadcast``, ``Balance``, ``Merge`` and ``Concat`` without the need for using the Graph DSL. The combine method takes care of constructing the necessary graph underneath. In following example we combine two sources into one (fan-in): ```csharp @@ -252,7 +252,7 @@ var sink = Sink.Combine(i => new Broadcast(i), sendRemotely, localProcessin Source.From(new[] {0, 1, 2}).RunWith(sink, materializer); ``` -#Building reusable Graph components +# Building reusable Graph components It is possible to build reusable, encapsulated components of arbitrary input and output ports using the graph DSL. As an example, we will build a graph junction that represents a pool of workers, where a worker is expressed @@ -307,7 +307,7 @@ public class PriorityWorkerPoolShape : Shape } ``` -#Predefined shapes +# Predefined shapes In general a custom `Shape` needs to be able to provide all its input and output ports, be able to copy itself, and also be able to create a new instance from given ports. There are some predefined shapes provided to avoid unnecessary boilerplate: @@ -398,7 +398,7 @@ RunnableGraph.FromGraph(GraphDsl.Create(b => })).Run(materializer); ``` -#Bidirectional Flows +# Bidirectional Flows A graph topology that is often useful is that of two flows going in opposite directions. Take for example a codec stage that serializes outgoing messages and deserializes incoming octet streams. Another such stage could add a framing protocol that attaches a length header to outgoing data and parses incoming frames back into the original octet stream chunks. These two stages are meant to be composed, applying one atop the other as part of a protocol stack. For this purpose exists the special type `BidiFlow` which is a graph that has exactly two open inlets and two open outlets. The corresponding shape is called `BidiShape` and is defined like this: ```csharp @@ -660,7 +660,7 @@ result.Result.ShouldAllBeEquivalentTo(Enumerable.Range(0, 10)); This example demonstrates how `BidiFlow` subgraphs can be hooked together and also turned around with the ``.Reversed`` method. The test simulates both parties of a network communication protocol without actually having to open a network connection—the flows can just be connected directly. -#Accessing the materialized value inside the Graph +# Accessing the materialized value inside the Graph In certain cases it might be necessary to feed back the materialized value of a Graph (partial, closed or backing a Source, Sink, Flow or BidiFlow). This is possible by using ``builder.MaterializedValue`` which gives an ``Outlet`` that can be used in the graph as an ordinary source or outlet, and which will eventually emit the materialized value. @@ -695,7 +695,7 @@ var cyclicAggregate = Source.FromGraph(GraphDsl.Create(Sink.Aggregate( })); ``` -#Graph cycles, liveness and deadlocks +# Graph cycles, liveness and deadlocks Cycles in bounded stream topologies need special considerations to avoid potential deadlocks and other liveness issues. This section shows several examples of problems that can arise from the presence of feedback arcs in stream processing graphs. The first example demonstrates a graph that contains a naïve cycle. The graph takes elements from the source, prints them, then broadcasts those elements to a consumer (we just used ``Sink.Ignore`` for now) and to a feedback arc that is merged back into the main stream via a ``Merge`` junction. diff --git a/docs/articles/streams/workingwithstreamingio.md b/docs/articles/streams/workingwithstreamingio.md index d79cbde9a98..af280bf5af8 100644 --- a/docs/articles/streams/workingwithstreamingio.md +++ b/docs/articles/streams/workingwithstreamingio.md @@ -3,7 +3,7 @@ layout: docs.hbs title: Working with streaming IO --- -#Streaming File IO +# Streaming File IO Akka Streams provide simple Sources and Sinks that can work with `ByteString` instances to perform IO operations on files. diff --git a/docs/articles/toc.yml b/docs/articles/toc.yml index eb22e8a5f6f..57b78187e55 100644 --- a/docs/articles/toc.yml +++ b/docs/articles/toc.yml @@ -6,10 +6,14 @@ href: intro/what-are-actors.md - name: Akka.NET Libraries and Modules href: intro/modules.md - - name: Getting Started - href: intro/getting-started.md - - name: The Obligatory Hello World - href: intro/the-obligatory-hello-world.md + - name: Part 1. Top-level Architecture + href: intro/tutorial-1.md + - name: Part 2. The Device Actor + href: intro/tutorial-2.md + - name: Part 3. Device Groups and Manager + href: intro/tutorial-3.md + - name: Part 4. Querying a Group of Devices + href: intro/tutorial-4.md - name: Use-case and Deployment Scenarios href: intro/use-case-and-deployment-scenarios.md - name: Production Users and Use Cases for Akka.NET @@ -97,7 +101,7 @@ - name: Buffers and working with rate href: streams/buffersandworkingwithrate.md - name: Custom stream processing - href: streams/customstreamprocessing.md + href: streams/custom-stream-processing.md - name: Integration href: streams/integration.md - name: Error Handling diff --git a/docs/articles/utilities/circuit-breaker.md b/docs/articles/utilities/circuit-breaker.md index b8ffca6e3cb..6472b0de241 100644 --- a/docs/articles/utilities/circuit-breaker.md +++ b/docs/articles/utilities/circuit-breaker.md @@ -47,14 +47,14 @@ Here's how a `CircuitBreaker` would be configured for: * a call timeout of 10 seconds * a reset timeout of 1 minute -[!code-csharp[Main](../../examples/Actors/UntypedActorAPI/Follower.cs?range=9-19,32-38)] +[!code-csharp[Main](../../examples/DocsExamples/Utilities/CircuitBreakerDocSpec.cs?name=circuit-breaker-usage)] ### Call Protection Here's how the `CircuitBreaker` would be used to protect an asynchronous call as well as a synchronous one: -[!code-csharp[Main](../../examples/Actors/UntypedActorAPI/Follower.cs?range=21-31)] +[!code-csharp[Main](../../examples/DocsExamples/Utilities/CircuitBreakerDocSpec.cs?name=call-protection)] ```csharp dangerousActor.Tell("is my middle name"); diff --git a/docs/articles/utilities/scheduler.md b/docs/articles/utilities/scheduler.md index 241aa19edbe..e4b5d4f941b 100644 --- a/docs/articles/utilities/scheduler.md +++ b/docs/articles/utilities/scheduler.md @@ -14,8 +14,12 @@ You can schedule sending of messages to actors and execution of tasks (`Action` delegate). You will get a `Task` back. By providing a `CancellationTokenSource` you can cancel the scheduled task. +The scheduler in Akka is designed for high-throughput of thousands up to millions of triggers. THe prime use-case being triggering Actor receive timeouts, Future timeouts, circuit breakers and other time dependent events which happen all-the-time and in many instances at the same time. The implementation is based on a Hashed Wheel Timer, which is a known datastrucure and algorithm for handling such use cases, refer to the [Hashed and Hierarchical Timing Wheels](http://www.cs.columbia.edu/~nahum/w6998/papers/sosp87-timing-wheels.pdf) whitepaper by Varghese and Lauck if you'd like to understand its inner workings. + +The Akka scheduler is **not** designed for long-term scheduling (see [Akka.Quartz.Actor](https://github.com/akkadotnet/Akka.Quartz.Actor) instead for this use-case) nor is it to be used for highly precise firing of the events. The maximum amount of time into the future you can schedule an event to trigger is around 8 months, which in practice is too much to be useful since this would assume the system never went down during that period. If you need long-term scheduling we highly recommend looking into alternative schedulers, as this is not the use-case the Akka scheduler is implemented for. + > [!WARNING] -> Scheduling timing is inexact. +> The default implementation of Scheduler used by Akka is based on job buckets which are emptied according to a fixed schedule. It does not execute tasks at the exact time, but on every tick, it will run everything that is (over)due. The accuracy of the default Scheduler can be modified by the `akka.scheduler.tick-duration` configuration property. ## Some examples @@ -25,9 +29,9 @@ var someActor = system.ActorOf("someActor"); var someMessage = new SomeMessage() {...}; system .Scheduler - .Schedule(TimeSpan.FromSeconds(0), + .ScheduleTellRepeatedly(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(5), - someActor, someMessage); + someActor, someMessage, ActorRefs.NoSender); //or ActorRefs.Nobody or something else ``` The above example will schedule "someMessage" to be sent to "someActor" @@ -40,3 +44,21 @@ the enclosing actor from within the closure. If you need to schedule an invocation it is better to use the `Schedule()` variant accepting a message and an `IActorRef` to schedule a message to self (containing the necessary parameters) and then call the method when the message is received. + +## From inside the actor + +``` +Context.Scheduler.ScheduleTellRepeatedly(....); +``` +> [!WARNING] +> All scheduled task will be executed when the `ActorSystem` is terminated. i.e. the task may execute before its timeout. + +## The scheduler interface +The actual scheduler implementation is defined by config and loaded upon ActorSystem start-up, which means that it is possible to provide a different one using the `akka.scheduler.implementation` configuration property. The referenced class must implement the `Akka.Actor.IScheduler` and `Akka.Actor.IAdvancedScheduler` interfaces + +##The cancellable interface + +Scheduling a task will result in a `ICancellable` or (or throw an `Exception` if attempted after the scheduler's shutdown). This allows you to cancel something that has been scheduled for execution. + +> [!WARNING] +> this does not abort the execution of the task, if it had already been started. diff --git a/docs/community/online-resources.md b/docs/community/online-resources.md index 01607652725..0c9146f9251 100644 --- a/docs/community/online-resources.md +++ b/docs/community/online-resources.md @@ -1,8 +1,10 @@ --- -layout: docs.hbs +uid: resources title: Resources -active_selector: resources --- + +# Resources + ## Akka.NET Bootcamp [Akka.NET Bootcamp]({{site.bootcamp_url}}) is a free, self-directed learning course brought to you by the folks at [Petabridge](https://petabridge.com). Over the three units of this bootcamp you will learn how to create fully-functional, real-world programs using Akka.NET actors and many other parts of the core Akka.NET framework. @@ -34,7 +36,7 @@ active_selector: resources - [Introduction to Akka.Cluster.Sharding in Akka.NET](https://petabridge.com/blog/introduction-to-cluster-sharding-akkadotnet/) (Bartosz Sypytkowski on January 17, 2017) - [Technical Overview of Akka.Cluster.Sharding in Akka.NET](https://petabridge.com/blog/cluster-sharding-technical-overview-akkadotnet/) (Bartosz Sypytkowski on January 31, 2017) - [Introduction to Distributed Publish-Subscribe in Akka.NET](https://petabridge.com/blog/distributed-pub-sub-intro-akkadotnet/) (Bartosz Sypytkowski on February 14, 2017) - +- [Introducing Petabridge.Cmd - a Command-line Management Tool for Akka.NET Applications](https://petabridge.com/blog/petabridgecmd-release/) (Aaron Stannard on June 7, 2017) **Others** - [Deploying actors with Akka.NET](https://rogeralsing.com/2014/03/09/deploying-actors-with-akka-net/) (Roger Johansson on March 9, 2014) @@ -42,7 +44,7 @@ active_selector: resources - [Map reduce with FSharp and Akka.net](http://bartoszsypytkowski.com/map-reduce-with-fsharp-and-akka-net/) (Bartosz Sypytkowski on July 8th, 2014) - [Actor supervisors in Akka.NET FSharp API](http://bartoszsypytkowski.com/actor-supervisors-in-akka-net-fsharp-api/) (Bartosz Sypytkowski on August 6th, 2014) - [Hipsterize your backend for The Greater Good with Akka.NET, F# and some DDD flavor](http://bartoszsypytkowski.com/hipsterize-your-backend-for-the-greater-good-with-akka-net-f-and-some-ddd-flavor/) (Bartosz Sypytkowski on October 26th, 2014) -- [Akka.NET – Concurrency control](https://rogeralsing.com/2014/11/10/akka-net-concurrency-control/) (Roger Johansson on November 10, 2014) +- [Akka.NET – Concurrency control](https://rogeralsing.com/2014/11/10/akka-net-concurrency-control/) (Roger Johansson on November 10th, 2014) - [Akka.NET remote deployment with F#](http://bartoszsypytkowski.com/akka-net-remote-deployment-with-f/) (Bartosz Sypytkowski on December 14th, 2014) - [An Actor Model Example with Akka.NET](http://blog.geist.no/an-actor-model-example-with-akka-net/) (Claus Sørensen on February 24th, 2015) - [Create your own Akka.NET persistence plugin](http://bartoszsypytkowski.com/create-your-own-akka-net-persistence-plugin/) (Bartosz Sypytkowski on March 28th, 2015) @@ -55,12 +57,20 @@ active_selector: resources - [Akka.NET underestimated features - Akka.IO](http://bartoszsypytkowski.com/akka-net-underestimated-feature-akka-io/) (Bartosz Sypytkowski on November 14th, 2015) - [Random things learned building Akka.NET – Part 1](https://rogeralsing.com/2016/03/13/random-things-learned-building-akka-net-part-1/) (Roger Johansson on March 13, 2016) - [Don't Ask, Tell](http://bartoszsypytkowski.com/dont-ask-tell-2/) (Bartosz Sypytkowski on May 3rd, 2016) +- [Monitoring Akka.NET Systems with Datadog](https://gregshackles.com/monitoring-akka-net-systems-with-datadog/) (Creg Shackles on May 25th, 2017) +- [Actor model and using of Akka.NET](https://rubikscode.net/2017/05/28/actor-model-and-using-of-akka-net/) (Nikola Živković on May 28th, 2017) ## Videos - [The Actor Model in F# and Akka.Net](https://www.youtube.com/watch?v=RiWXo_5CAvg) (March 17, 2015) - [Streaming ETL w/ Akka.NET](https://vimeo.com/123452527) (Andrew Skotzko on March 18, 2015) - [Akka.NET Internals: How Akka.Remote Connections Work](https://www.youtube.com/watch?v=6c1gVLyYcMM) (Aaron Stannard on May 5, 2015) -- [Full-Stack, Message-Oriented Programming with Akka.NET Actors](https://www.youtube.com/watch?v=nPGMVhI7zyk) (Andrew Skotzko on 8 December, 2015) +- [Full-Stack, Message-Oriented Programming with Akka.NET Actors](https://www.youtube.com/watch?v=nPGMVhI7zyk) (Andrew Skotzko on 8th December, 2015) +- [Akka.NET: The Future of Distributed Programming in .NET](https://www.youtube.com/watch?v=ozelpjr9SXE) (Aaron Stannard on August 31, 2016) +- [Life with actors: experience report](https://www.youtube.com/watch?v=KQwskUjsSi8) (Vagif Abilov and Erlend Wiig on February 16th, 2017) +- [Akka.NET: The Future of Distributed Programming in .NET](https://www.youtube.com/watch?v=Q3SzfO8jloc) (Aaron Stannard on June 8th, 2017) +- [Easy Eventual Consistency with Actor Models + Amazon Web Services](https://www.youtube.com/watch?v=PJT9D_4uUEg) (Philip Laureano on July 5th, 2017) +- [Composing high performance process workflows with Akka Streams](https://www.youtube.com/watch?v=kWU_LxYXMjE) (Vagif Abilov on July 5th, 2017) +- [Getting real(time) with Akka.NET, React and Redux](https://www.youtube.com/watch?v=irvm5EdHQc0) (Francis Paulin on July 5th, 2017) ## Courses - [Building Concurrent Applications with the Actor Model in Akka.NET (Pluralsight)](https://www.pluralsight.com/courses/akka-dotnet-actor-model-building-concurrent-applications) (Jason Roberts on 5 August 2015) @@ -88,8 +98,3 @@ active_selector: resources - [Writing scalable and distributed systems with Akka.NET](https://www.youtube.com/watch?v=fwWA6Bugg_c) (Nikita Tsukanov on June 5, 2015) - [Actor Model on .NET (in Russian)](https://www.youtube.com/watch?v=jek8Qmc3ZjQ) (Anton Moldovan on October 30, 2015) - [Actor-based Concurrency with F# and Akka.NET (in Russian)](https://www.youtube.com/watch?v=LLG8_0XtD4o) (Akim Boyko on 19 December, 2015) - -## Notable materials from Akka JVM world -- [Above the Clouds: Introducing Akka](https://www.youtube.com/watch?v=UY3fuHebRMI) - Geared towards Akka in Java. Gives an overview of the Actor model -- [Up, Up, and Out: Scaling Software with Akka](https://www.youtube.com/watch?v=GBvtE61Wrto) - Introduction to Akka -- [Building Reactive Applications with Akka](https://www.youtube.com/watch?v=6Cb1wSVRI-Q) - Jonas Bonér (creator of original Akka project) explains the Reactive Model and Akka. diff --git a/docs/docfx.json b/docs/docfx.json index 65401776382..b6d5a5075f1 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -1,76 +1,62 @@ { - "metadata": [ - { - "src": [ - { - "files": [ - "**/Akka.csproj", - "**/Akka.Persistence.csproj", - "**/Akka.Persistence.Query.csproj", - "**/Akka.Streams.csproj", - "**/Akka.Remote.csproj", - "**/Akka.Cluster.csproj", - "**/Akka.TestKit.csproj", - "**/Akka.Cluster.Tools.csproj", - "**/Akka.Cluster.Sharding.csproj", - "**/Akka.DistributedData.csproj" - ], - "exclude": [ - "**/obj/**", - "**/bin/**", - "_site/**" - ], - "src": "../src" - } + "metadata": [{ + "src": [{ + "files": [ "**/*.csproj" ], + "exclude": [ + "**/obj/**", + "**/bin/**", + "_site/**", + "**/examples/**", + "**/benchmark/**", + "**/*TestRunner*.csproj", + "**/*Tests*.csproj", + "**/*Tests.*.csproj" ], - "dest": "api" - } - ], + "src": "../src" + }], + "dest": "api", + "properties": { + "TargetFramework": "net45" + } + }], "build": { - "content": [ - { - "files": [ - "api/**.yml", - "api/index.md" - ] - }, - { - "files": [ - "articles/**.md", - "articles/**/toc.yml", - "community/**.md", - "community/**/toc.yml", - "toc.yml", - "*.md" - ], - "exclude": [ - "obj/**", - "_site/**" - ] - } - ], - "resource": [ - { - "files": [ - "images/**" - ], - "exclude": [ - "obj/**", - "_site/**" - ] - } - ], - "overwrite": [ - { - "files": [ - "apidoc/**.md" - ], - "exclude": [ - "obj/**", - "_site/**" - ] - } - ], + "content": [{ + "files": [ + "api/**.yml", + "api/index.md" + ] + }, { + "files": [ + "articles/**.md", + "articles/**/toc.yml", + "community/**.md", + "community/**/toc.yml", + "toc.yml", + "*.md" + ], + "exclude": [ + "obj/**", + "_site/**" + ] + }], + "resource": [{ + "files": [ + "images/**" + ], + "exclude": [ + "obj/**", + "_site/**" + ] + }], + "overwrite": [{ + "files": [ + "apidoc/**.md" + ], + "exclude": [ + "obj/**", + "_site/**" + ] + }], "globalMetadata": { "_appTitle": "Akka.NET Documentation", "_appLogoPath": "/images/akkalogo.png", @@ -85,6 +71,6 @@ "template" ], "postProcessors": [], - "noLangKeyword": false + "noLangKeyword": false, } } \ No newline at end of file diff --git a/docs/examples/DocsExamples.sln b/docs/examples/DocsExamples.sln index 057bb71b4b9..e1a29dbeb33 100644 --- a/docs/examples/DocsExamples.sln +++ b/docs/examples/DocsExamples.sln @@ -1,9 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26403.7 +VisualStudioVersion = 15.0.26430.14 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocsExamples", "DocsExamples.csproj", "{47E0257B-23D0-4D0E-B567-4DFCC3B2B2E1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocsExamples", "DocsExamples\DocsExamples.csproj", "{47E0257B-23D0-4D0E-B567-4DFCC3B2B2E1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tutorials", "Tutorials\Tutorials.csproj", "{3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -27,6 +29,18 @@ Global {47E0257B-23D0-4D0E-B567-4DFCC3B2B2E1}.Release|x64.Build.0 = Release|Any CPU {47E0257B-23D0-4D0E-B567-4DFCC3B2B2E1}.Release|x86.ActiveCfg = Release|Any CPU {47E0257B-23D0-4D0E-B567-4DFCC3B2B2E1}.Release|x86.Build.0 = Release|Any CPU + {3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}.Debug|x64.ActiveCfg = Debug|Any CPU + {3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}.Debug|x64.Build.0 = Debug|Any CPU + {3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}.Debug|x86.ActiveCfg = Debug|Any CPU + {3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}.Debug|x86.Build.0 = Debug|Any CPU + {3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}.Release|Any CPU.Build.0 = Release|Any CPU + {3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}.Release|x64.ActiveCfg = Release|Any CPU + {3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}.Release|x64.Build.0 = Release|Any CPU + {3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}.Release|x86.ActiveCfg = Release|Any CPU + {3C3559CC-D45D-4621-BB81-FCD6E7B38B4A}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/docs/examples/Actors/FiniteStateMachine/ExampleFSMActor.cs b/docs/examples/DocsExamples/Actors/FiniteStateMachine/ExampleFSMActor.cs similarity index 100% rename from docs/examples/Actors/FiniteStateMachine/ExampleFSMActor.cs rename to docs/examples/DocsExamples/Actors/FiniteStateMachine/ExampleFSMActor.cs diff --git a/docs/examples/Actors/FiniteStateMachine/ExampleFSMActorTests.cs b/docs/examples/DocsExamples/Actors/FiniteStateMachine/ExampleFSMActorTests.cs similarity index 100% rename from docs/examples/Actors/FiniteStateMachine/ExampleFSMActorTests.cs rename to docs/examples/DocsExamples/Actors/FiniteStateMachine/ExampleFSMActorTests.cs diff --git a/docs/examples/Actors/FiniteStateMachine/FiniteStateMachine.Messages.cs b/docs/examples/DocsExamples/Actors/FiniteStateMachine/FiniteStateMachine.Messages.cs similarity index 100% rename from docs/examples/Actors/FiniteStateMachine/FiniteStateMachine.Messages.cs rename to docs/examples/DocsExamples/Actors/FiniteStateMachine/FiniteStateMachine.Messages.cs diff --git a/docs/examples/Actors/ReceiveActorAPI/Follower.cs b/docs/examples/DocsExamples/Actors/ReceiveActorAPI/Follower.cs similarity index 100% rename from docs/examples/Actors/ReceiveActorAPI/Follower.cs rename to docs/examples/DocsExamples/Actors/ReceiveActorAPI/Follower.cs diff --git a/docs/examples/Actors/UntypedActorAPI/Follower.cs b/docs/examples/DocsExamples/Actors/UntypedActorAPI/Follower.cs similarity index 100% rename from docs/examples/Actors/UntypedActorAPI/Follower.cs rename to docs/examples/DocsExamples/Actors/UntypedActorAPI/Follower.cs diff --git a/docs/examples/DocsExamples/DocsExamples.csproj b/docs/examples/DocsExamples/DocsExamples.csproj new file mode 100644 index 00000000000..457219cde83 --- /dev/null +++ b/docs/examples/DocsExamples/DocsExamples.csproj @@ -0,0 +1,25 @@ + + + + Exe + net461 + win-x64 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/examples/Networking/ClusterClient/ClientListener.cs b/docs/examples/DocsExamples/Networking/ClusterClient/ClientListener.cs similarity index 100% rename from docs/examples/Networking/ClusterClient/ClientListener.cs rename to docs/examples/DocsExamples/Networking/ClusterClient/ClientListener.cs diff --git a/docs/examples/Networking/ClusterClient/ReceptionistListener.cs b/docs/examples/DocsExamples/Networking/ClusterClient/ReceptionistListener.cs similarity index 100% rename from docs/examples/Networking/ClusterClient/ReceptionistListener.cs rename to docs/examples/DocsExamples/Networking/ClusterClient/ReceptionistListener.cs diff --git a/docs/examples/Networking/IO/EchoConnection.cs b/docs/examples/DocsExamples/Networking/IO/EchoConnection.cs similarity index 90% rename from docs/examples/Networking/IO/EchoConnection.cs rename to docs/examples/DocsExamples/Networking/IO/EchoConnection.cs index df698b73bb5..7a5b41391b1 100644 --- a/docs/examples/Networking/IO/EchoConnection.cs +++ b/docs/examples/DocsExamples/Networking/IO/EchoConnection.cs @@ -1,5 +1,6 @@ using Akka.Actor; using Akka.IO; +using Akka.Util.Internal; namespace DocsExamples.Networking.IO { @@ -17,7 +18,7 @@ protected override void OnReceive(object message) if (message is Tcp.Received) { var received = message as Tcp.Received; - if (received.Data.Head == 'x') + if (received.Data[0] == 'x') Context.Stop(Self); else _connection.Tell(Tcp.Write.Create(received.Data)); diff --git a/docs/examples/Networking/IO/EchoServer.cs b/docs/examples/DocsExamples/Networking/IO/EchoServer.cs similarity index 100% rename from docs/examples/Networking/IO/EchoServer.cs rename to docs/examples/DocsExamples/Networking/IO/EchoServer.cs diff --git a/docs/examples/Networking/IO/TelnetClient.cs b/docs/examples/DocsExamples/Networking/IO/TelnetClient.cs similarity index 100% rename from docs/examples/Networking/IO/TelnetClient.cs rename to docs/examples/DocsExamples/Networking/IO/TelnetClient.cs diff --git a/docs/examples/DocsExamples/Networking/Serialization/CreateCustomSerializer.cs b/docs/examples/DocsExamples/Networking/Serialization/CreateCustomSerializer.cs new file mode 100644 index 00000000000..99c8c272e17 --- /dev/null +++ b/docs/examples/DocsExamples/Networking/Serialization/CreateCustomSerializer.cs @@ -0,0 +1,43 @@ +using System; +using Akka.Actor; +using Akka.Serialization; + +namespace DocsExamples.Networking.Serialization +{ + public class MySerializer : Serializer + { + public MySerializer(ExtendedActorSystem system) : base(system) + { + } + + /// + /// This is whether requires a or not + /// + public override bool IncludeManifest { get; } = false; + + /// + /// Completely unique value to identify this implementation of the + /// used to optimize network traffic + /// 0 - 40 is reserved by Akka.NET itself + /// + public override int Identifier => 1234567; + + /// + /// Serializes the given object to an Array of Bytes + /// + public override byte[] ToBinary(object obj) + { + // Put the real code that serializes the object here + throw new NotImplementedException(); + } + + /// + /// Deserializes the given array, using the type hint (if any, see above) + /// + public override object FromBinary(byte[] bytes, Type type) + { + // Put the real code that deserializes here + throw new NotImplementedException(); + } + } +} diff --git a/docs/examples/DocsExamples/Networking/Serialization/ExternalAddressProvider.cs b/docs/examples/DocsExamples/Networking/Serialization/ExternalAddressProvider.cs new file mode 100644 index 00000000000..afe2e7cfea6 --- /dev/null +++ b/docs/examples/DocsExamples/Networking/Serialization/ExternalAddressProvider.cs @@ -0,0 +1,40 @@ +using System; +using Akka.Actor; +using Akka.Util.Internal; + +namespace DocsExamples.Networking.Serialization +{ + public class ExternalAddress : ExtensionIdProvider + { + public override ExternalAddressExtension CreateExtension(ExtendedActorSystem system) => + new ExternalAddressExtension(system); + } + + public class ExternalAddressExtension : IExtension + { + private readonly ExtendedActorSystem _system; + + public ExternalAddressExtension(ExtendedActorSystem system) + { + _system = system; + } + + public Address AddressFor(Address remoteAddr) + { + return _system.Provider.GetExternalAddressFor(remoteAddr) + ?? throw new InvalidOperationException($"cannot send to {remoteAddr}"); + } + } + + public class Test + { + private ExtendedActorSystem ExtendedSystem => + ActorSystem.Create("test").AsInstanceOf(); + + public string SerializeTo(IActorRef actorRef, Address remote) + { + return actorRef.Path.ToSerializationFormatWithAddress( + new ExternalAddress().Get(ExtendedSystem).AddressFor(remote)); + } + } +} diff --git a/docs/examples/DocsExamples/Networking/Serialization/MyOwnSerializer2.cs b/docs/examples/DocsExamples/Networking/Serialization/MyOwnSerializer2.cs new file mode 100644 index 00000000000..d28122b3978 --- /dev/null +++ b/docs/examples/DocsExamples/Networking/Serialization/MyOwnSerializer2.cs @@ -0,0 +1,87 @@ +using System; +using System.Runtime.Serialization; +using System.Text; +using Akka.Actor; +using Akka.Serialization; + +namespace DocsExamples.Networking.Serialization +{ + public class MyOwnSerializer2 : SerializerWithStringManifest + { + private const string CustomerManifest = "customer"; + private const string UserManifest = "user"; + + public MyOwnSerializer2(ExtendedActorSystem system) : base(system) + { + } + + /// + /// Completely unique value to identify this implementation of the + /// used to optimize network traffic + /// 0 - 40 is reserved by Akka.NET itself + /// + public override int Identifier { get; } = 1234567; + + /// + /// The manifest (type hint) that will be provided in the fromBinary method Use if manifest is not needed. + /// + public override string Manifest(object obj) + { + switch (obj) + { + case Customer _: return CustomerManifest; + case User _: return UserManifest; + } + + throw new NotImplementedException(); + } + + /// + /// Serializes the given object to an Array of Bytes + /// + public override byte[] ToBinary(object obj) + { + // Put the real code that serializes the object here + switch (obj) + { + case Customer c: return Encoding.UTF8.GetBytes(c.Name); + case User c: return Encoding.UTF8.GetBytes(c.Name); + } + + throw new NotImplementedException(); + } + + /// + /// Deserializes the given array, using the type hint + /// + public override object FromBinary(byte[] bytes, string manifest) + { + switch (manifest) + { + case CustomerManifest: return new Customer(Encoding.UTF8.GetString(bytes)); + case UserManifest: return new User(Encoding.UTF8.GetString(bytes)); + default: throw new SerializationException(); + } + } + } + + public class Customer + { + public Customer(string name) + { + Name = name; + } + + public string Name { get; set; } + } + + public class User + { + public User(string name) + { + Name = name; + } + + public string Name { get; set; } + } +} diff --git a/docs/examples/Persistence/AtLeastOnceDelivery/AtLeastOnceDeliveryActor.Messages.cs b/docs/examples/DocsExamples/Persistence/AtLeastOnceDelivery/AtLeastOnceDeliveryActor.Messages.cs similarity index 100% rename from docs/examples/Persistence/AtLeastOnceDelivery/AtLeastOnceDeliveryActor.Messages.cs rename to docs/examples/DocsExamples/Persistence/AtLeastOnceDelivery/AtLeastOnceDeliveryActor.Messages.cs diff --git a/docs/examples/Persistence/AtLeastOnceDelivery/ExampleAtLeastOnceDeliveryActor.cs b/docs/examples/DocsExamples/Persistence/AtLeastOnceDelivery/ExampleAtLeastOnceDeliveryActor.cs similarity index 100% rename from docs/examples/Persistence/AtLeastOnceDelivery/ExampleAtLeastOnceDeliveryActor.cs rename to docs/examples/DocsExamples/Persistence/AtLeastOnceDelivery/ExampleAtLeastOnceDeliveryActor.cs diff --git a/docs/examples/Persistence/AtLeastOnceDelivery/ExampleAtLeastOnceDeliveryReceiveActor.cs b/docs/examples/DocsExamples/Persistence/AtLeastOnceDelivery/ExampleAtLeastOnceDeliveryReceiveActor.cs similarity index 100% rename from docs/examples/Persistence/AtLeastOnceDelivery/ExampleAtLeastOnceDeliveryReceiveActor.cs rename to docs/examples/DocsExamples/Persistence/AtLeastOnceDelivery/ExampleAtLeastOnceDeliveryReceiveActor.cs diff --git a/docs/examples/Persistence/PersistentActor/AvoidPoisonPill.cs b/docs/examples/DocsExamples/Persistence/PersistentActor/AvoidPoisonPill.cs similarity index 100% rename from docs/examples/Persistence/PersistentActor/AvoidPoisonPill.cs rename to docs/examples/DocsExamples/Persistence/PersistentActor/AvoidPoisonPill.cs diff --git a/docs/examples/Persistence/PersistentActor/Defer.cs b/docs/examples/DocsExamples/Persistence/PersistentActor/Defer.cs similarity index 100% rename from docs/examples/Persistence/PersistentActor/Defer.cs rename to docs/examples/DocsExamples/Persistence/PersistentActor/Defer.cs diff --git a/docs/examples/Persistence/PersistentActor/DeferWithPersist.cs b/docs/examples/DocsExamples/Persistence/PersistentActor/DeferWithPersist.cs similarity index 100% rename from docs/examples/Persistence/PersistentActor/DeferWithPersist.cs rename to docs/examples/DocsExamples/Persistence/PersistentActor/DeferWithPersist.cs diff --git a/docs/examples/Persistence/PersistentActor/NestedPersists.cs b/docs/examples/DocsExamples/Persistence/PersistentActor/NestedPersists.cs similarity index 100% rename from docs/examples/Persistence/PersistentActor/NestedPersists.cs rename to docs/examples/DocsExamples/Persistence/PersistentActor/NestedPersists.cs diff --git a/docs/examples/Persistence/PersistentActor/NestedPersistsAsync.cs b/docs/examples/DocsExamples/Persistence/PersistentActor/NestedPersistsAsync.cs similarity index 100% rename from docs/examples/Persistence/PersistentActor/NestedPersistsAsync.cs rename to docs/examples/DocsExamples/Persistence/PersistentActor/NestedPersistsAsync.cs diff --git a/docs/examples/Persistence/PersistentActor/PersistAsync.cs b/docs/examples/DocsExamples/Persistence/PersistentActor/PersistAsync.cs similarity index 100% rename from docs/examples/Persistence/PersistentActor/PersistAsync.cs rename to docs/examples/DocsExamples/Persistence/PersistentActor/PersistAsync.cs diff --git a/docs/examples/Persistence/PersistentActor/PersistentActor.cs b/docs/examples/DocsExamples/Persistence/PersistentActor/PersistentActor.cs similarity index 100% rename from docs/examples/Persistence/PersistentActor/PersistentActor.cs rename to docs/examples/DocsExamples/Persistence/PersistentActor/PersistentActor.cs diff --git a/docs/examples/Persistence/PersistentActor/Snapshots.cs b/docs/examples/DocsExamples/Persistence/PersistentActor/Snapshots.cs similarity index 100% rename from docs/examples/Persistence/PersistentActor/Snapshots.cs rename to docs/examples/DocsExamples/Persistence/PersistentActor/Snapshots.cs diff --git a/docs/examples/DocsExamples/Persistence/WebStoreCustomerFSMActor.cs b/docs/examples/DocsExamples/Persistence/WebStoreCustomerFSMActor.cs new file mode 100644 index 00000000000..babb649466d --- /dev/null +++ b/docs/examples/DocsExamples/Persistence/WebStoreCustomerFSMActor.cs @@ -0,0 +1,300 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using Akka.Persistence.Fsm; +using Akka.Actor; + +namespace DocsExamples.Persistence.PersistentFSM +{ + #region persistent-fsm-commands + public interface ICommand { } + + public class AddItem : ICommand + { + public AddItem(Item item) + { + Item = item; + } + + public Item Item { get; set; } + } + + public class Buy : ICommand + { + public static Buy Instance { get; } = new Buy(); + private Buy() { } + } + + public class Leave : ICommand + { + public static Leave Instance { get; } = new Leave(); + private Leave() { } + } + + public class GetCurrentCart : ICommand + { + public static GetCurrentCart Instance { get; } = new GetCurrentCart(); + private GetCurrentCart() { } + } + #endregion + + #region persistent-fsm-states + public interface IUserState : Akka.Persistence.Fsm.PersistentFSM.IFsmState { } + + public class LookingAround : IUserState + { + public static LookingAround Instance { get; } = new LookingAround(); + private LookingAround() { } + public string Identifier => "Looking Around"; + } + + public class Shopping : IUserState + { + public static Shopping Instance { get; } = new Shopping(); + private Shopping() { } + public string Identifier => "Shopping"; + } + + public class Inactive : IUserState + { + public static Inactive Instance { get; } = new Inactive(); + private Inactive() { } + public string Identifier => "Inactive"; + } + + public class Paid : IUserState + { + public static Paid Instance { get; } = new Paid(); + private Paid() { } + public string Identifier => "Paid"; + } + #endregion + + #region persistent-fsm-domain-events + public interface IDomainEvent { } + + public class ItemAdded : IDomainEvent + { + public ItemAdded(Item item) + { + Item = item; + } + + public Item Item { get; set; } + } + + public class OrderExecuted : IDomainEvent + { + public static OrderExecuted Instance { get; } = new OrderExecuted(); + private OrderExecuted() { } + } + + public class OrderDiscarded : IDomainEvent + { + public static OrderDiscarded Instance { get; } = new OrderDiscarded(); + private OrderDiscarded() { } + } + #endregion + + #region persistent-fsm-domain-messages + public class Item + { + public Item(string id, string name, double price) + { + Id = id; + Name = name; + Price = price; + } + + public string Id { get; } + + public string Name { get; } + + public double Price { get; } + } + + public interface IShoppingCart + { + IShoppingCart AddItem(Item item); + IShoppingCart Empty(); + } + + public class EmptyShoppingCart : IShoppingCart + { + public IShoppingCart AddItem(Item item) + { + return new NonEmptyShoppingCart(ImmutableList.Create(item)); + } + + public IShoppingCart Empty() + { + return this; + } + } + + public class NonEmptyShoppingCart : IShoppingCart + { + public NonEmptyShoppingCart(ImmutableList items) + { + Items = items; + } + + public IShoppingCart AddItem(Item item) + { + return new NonEmptyShoppingCart(Items.Add(item)); + } + + public IShoppingCart Empty() + { + return new EmptyShoppingCart(); + } + + public ImmutableList Items { get; } + } + #endregion + + #region persistent-fsm-side-effects + public interface IReportEvent { } + + public class PurchaseWasMade : IReportEvent + { + public PurchaseWasMade(IEnumerable items) + { + Items = items; + } + + public IEnumerable Items { get; } + } + + public class ShoppingCardDiscarded : IReportEvent + { + public static ShoppingCardDiscarded Instance { get; } = new ShoppingCardDiscarded(); + private ShoppingCardDiscarded() { } + } + #endregion + + internal class WebStoreCustomerFSMActor : PersistentFSM + { + public WebStoreCustomerFSMActor(string persistenceId, IActorRef reportActor) + { + PersistenceId = persistenceId; + + #region persistent-fsm-setup + StartWith(LookingAround.Instance, new EmptyShoppingCart()); + + When(LookingAround.Instance, (evt, state) => + { + if (evt.FsmEvent is AddItem addItem) + { + return GoTo(Shopping.Instance) + .Applying(new ItemAdded(addItem.Item)) + .ForMax(TimeSpan.FromSeconds(1)); + } + else if (evt.FsmEvent is GetCurrentCart) + { + return Stay().Replying(evt.StateData); + } + + return Stay(); + }); + + When(Shopping.Instance, (evt, state) => + { + if (evt.FsmEvent is AddItem addItem) + { + return Stay() + .Applying(new ItemAdded(addItem.Item)) + .ForMax(TimeSpan.FromSeconds(1)); + } + else if (evt.FsmEvent is Buy) + { + return GoTo(Paid.Instance).Applying(OrderExecuted.Instance) + .AndThen(cart => + { + if (cart is NonEmptyShoppingCart nonShoppingCart) + { + reportActor.Tell(new PurchaseWasMade(nonShoppingCart.Items)); + SaveStateSnapshot(); + } + else if (cart is EmptyShoppingCart) + { + SaveStateSnapshot(); + } + }); + } + else if (evt.FsmEvent is Leave) + { + return Stop().Applying(OrderDiscarded.Instance) + .AndThen(cart => + { + reportActor.Tell(ShoppingCardDiscarded.Instance); + SaveStateSnapshot(); + }); + } + else if (evt.FsmEvent is GetCurrentCart) + { + return Stay().Replying(evt.StateData); + } + else if (evt.FsmEvent is FSMBase.StateTimeout) + { + return GoTo(Inactive.Instance).ForMax(TimeSpan.FromSeconds(2)); + } + + return Stay(); + }); + + When(Inactive.Instance, (evt, state) => + { + if (evt.FsmEvent is AddItem addItem) + { + return GoTo(Shopping.Instance) + .Applying(new ItemAdded(addItem.Item)) + .ForMax(TimeSpan.FromSeconds(1)); + } + else if (evt.FsmEvent is FSMBase.StateTimeout) + { + return Stop() + .Applying(OrderDiscarded.Instance) + .AndThen(cart => reportActor.Tell(ShoppingCardDiscarded.Instance)); + } + + return Stay(); + }); + + When(Paid.Instance, (evt, state) => + { + if (evt.FsmEvent is Leave) + { + return Stop(); + } + else if (evt.FsmEvent is GetCurrentCart) + { + return Stay().Replying(evt.StateData); + } + + return Stay(); + }); + #endregion + } + + public override string PersistenceId { get; } + + internal static Props Props(string name, IActorRef dummyReportActorRef) + { + return Akka.Actor.Props.Create(() => new WebStoreCustomerFSMActor(name, dummyReportActorRef)); + } + + #region persistent-fsm-apply-event + protected override IShoppingCart ApplyEvent(IDomainEvent evt, IShoppingCart cartBeforeEvent) + { + switch (evt) + { + case ItemAdded itemAdded: return cartBeforeEvent.AddItem(itemAdded.Item); + case OrderExecuted _: return cartBeforeEvent; + case OrderDiscarded _: return cartBeforeEvent.Empty(); + default: return cartBeforeEvent; + } + } + #endregion + } +} diff --git a/docs/examples/Program.cs b/docs/examples/DocsExamples/Program.cs similarity index 100% rename from docs/examples/Program.cs rename to docs/examples/DocsExamples/Program.cs diff --git a/docs/examples/DocsExamples/Testkit/ParentSampleTest.cs b/docs/examples/DocsExamples/Testkit/ParentSampleTest.cs new file mode 100644 index 00000000000..46c6de01dba --- /dev/null +++ b/docs/examples/DocsExamples/Testkit/ParentSampleTest.cs @@ -0,0 +1,105 @@ +using System; +using System.Runtime.Remoting.Messaging; +using Akka.Actor; +using Akka.Actor.Dsl; +using Akka.TestKit.Xunit2; +using Akka.Actor.Dsl; +using Xunit; + +namespace DocsExamples.Testkit +{ + public class ParentSampleTest : TestKit + { + class Parent : ReceiveActor + { + private IActorRef child; + private bool ponged = false; + + public Parent() + { + child = Context.ActorOf(Props.Create(), "child"); + Receive(str => str.Equals("pingit"), m => + { + child.Tell("ping"); + }); + Receive(str => str.Equals("pong"), m => + { + ponged = true; + }); + } + } + + class Child : ReceiveActor + { + public Child() + { + Receive(str => str.Equals("ping"), m => + { + Context.Parent.Tell("pong"); + }); + } + } + + + class DependentChild : ReceiveActor + { + private IActorRef parent; + + public DependentChild(IActorRef parent) + { + this.parent = parent; + + Receive(s => s.Equals("ping"), m => + { + parent.Tell("pong", Self); + }); + } + } + + [Fact] + public void Fabricated_Parent_Should_Test_Child_Responses() + { + var proxy = CreateTestProbe(); + Action actor = d => + { + IActorRef child = null; + d.OnPreStart = context => child = context.ActorOf("child"); + d.ReceiveAny((m,c) => + { + if(c.Sender.Equals(child)) + proxy.Ref.Forward(m); + else + { + child.Forward(m); + } + }); + }; + + var parent = Sys.ActorOf(Props.Create(() => new Act(actor))); + proxy.Send(parent, "ping"); + proxy.ExpectMsg("pong"); + } + + + class GenericDependentParent : ReceiveActor + { + private IActorRef child; + private bool ponged; + + public GenericDependentParent(Func childMaker) + { + child = childMaker(Context); + ponged = false; + + Receive(str => str.Equals("pingit"), m => + { + child.Tell("ping"); + }); + Receive(str => str.Equals("pong"), m => + { + ponged = true; + }); + } + } + } +} \ No newline at end of file diff --git a/docs/examples/DocsExamples/Testkit/ProbeSampleTest.cs b/docs/examples/DocsExamples/Testkit/ProbeSampleTest.cs new file mode 100644 index 00000000000..7e1be5a135e --- /dev/null +++ b/docs/examples/DocsExamples/Testkit/ProbeSampleTest.cs @@ -0,0 +1,90 @@ +using Akka.Actor; +using Akka.TestKit; +using Akka.TestKit.Xunit2; +using Xunit; + +namespace DocsExamples.Testkit +{ + public class ProbeSampleTest : TestKit + { + public class Forwarder : ReceiveActor + { + private IActorRef target; + + public Forwarder(IActorRef target) + { + this.target = target; + + ReceiveAny(target.Forward); + } + } + + [Fact] + public void Test() + { + //create a test probe + var probe = CreateTestProbe(); + + //create a forwarder, injecting the probo's testActor + var props = Props.Create(new Forwarder(probe)); + var forwarder = Sys.ActorOf(props, "forwarder"); + + //verify correct forwarding + forwarder.Tell(43, TestActor); + probe.ExpectMsg(42); + Assert.Equal(TestActor, probe.LastSender); + } + + [Fact] + public void MultipleProbes() + { + var worker = CreateTestProbe("worker"); + var aggregator = CreateTestProbe("aggregator"); + + Assert.True(worker.Ref.Path.Name.StartsWith("worker")); + Assert.True(aggregator.Ref.Path.Name.StartsWith("aggregator")); + } + + [Fact] + public void ReplyingToProbeMessages() + { + + var probe = CreateTestProbe(); + probe.Tell("hello"); + probe.ExpectMsg("hello"); + probe.Reply("world"); + ExpectMsg("world"); + Assert.Equal(probe.Ref, LastSender); + } + + [Fact] + public void ForwardingProbeMessages() + { + var probe = CreateTestProbe(); + probe.Tell("hello"); + probe.ExpectMsg("hello"); + probe.Forward(TestActor); + ExpectMsg("hello"); + Assert.Equal(TestActor, LastSender); + } + + [Fact] + public void ProbeAutopilot() + { + var probe = CreateTestProbe(); + probe.SetAutoPilot(new DelegateAutoPilot((sender, message) => + { + sender.Tell(message, ActorRefs.NoSender); + return AutoPilot.NoAutoPilot; + })); + + //first one is replied to directly + probe.Tell("Hello"); + ExpectMsg("Hello"); + //... but then the auto-pilot switched itself off + probe.Tell("world"); + ExpectNoMsg(); + } + + } +} \ No newline at end of file diff --git a/docs/examples/DocsExamples/Testkit/TestKitSampleTest.cs b/docs/examples/DocsExamples/Testkit/TestKitSampleTest.cs new file mode 100644 index 00000000000..68a23a3fd60 --- /dev/null +++ b/docs/examples/DocsExamples/Testkit/TestKitSampleTest.cs @@ -0,0 +1,64 @@ +using System; +using Akka.Actor; +using Akka.TestKit.Xunit2; +using Xunit; + +namespace DocsExamples.Testkit +{ + + public class SomeActor : ReceiveActor + { + IActorRef target = null; + + public SomeActor() + { + Receive(s => s.Equals("hello"), (message) => { + Sender.Tell("world", Self); + if (target != null) + target.Forward(message); + }); + + Receive(actorRef => { + target = actorRef; + Sender.Tell("done"); + }); + } + } + + public class TestKitSampleTest : TestKit + { + + [Fact] + public void Test() + { + var subject = this.Sys.ActorOf(); + + var probe = this.CreateTestProbe(); + + //inject the probe by passing it to the test subject + //like a real resource would be passing in production + subject.Tell(probe.Ref, this.TestActor); + + ExpectMsg("done", TimeSpan.FromSeconds(1)); + + // the action needs to finish within 3 seconds + Within(TimeSpan.FromSeconds(3), () => { + subject.Tell("hello", this.TestActor); + + // This is a demo: would normally use expectMsgEquals(). + // Wait time is bounded by 3-second deadline above. + AwaitCondition(() => probe.HasMessages); + + // response must have been enqueued to us before probe + ExpectMsg("world", TimeSpan.FromSeconds(0)); + // check that the probe we injected earlier got the msg + probe.ExpectMsg("hello", TimeSpan.FromSeconds(0)); + + Assert.Equal(TestActor, probe.Sender); + + // Will wait for the rest of the 3 seconds + ExpectNoMsg(); + }); + } + } +} diff --git a/docs/examples/DocsExamples/Testkit/WithinSampleTest.cs b/docs/examples/DocsExamples/Testkit/WithinSampleTest.cs new file mode 100644 index 00000000000..a19552c4f0a --- /dev/null +++ b/docs/examples/DocsExamples/Testkit/WithinSampleTest.cs @@ -0,0 +1,20 @@ +using Akka.Actor; +using Akka.TestKit.Xunit2; +using FluentAssertions; +using Xunit; + +namespace DocsExamples.Testkit +{ + public class WithinSampleTest : TestKit + { + [Fact] + public void WithinSample() + { + TestActor.Tell(42, ActorRefs.NoSender); + Within(0.Milliseconds(), 1.Seconds(), () => + { + Assert.Equal(42, ExpectMsg()); + }); + } + } +} \ No newline at end of file diff --git a/docs/examples/Utilities/CircuitBreakers/DangerousActor.cs b/docs/examples/DocsExamples/Utilities/CircuitBreakerDocSpec.cs similarity index 63% rename from docs/examples/Utilities/CircuitBreakers/DangerousActor.cs rename to docs/examples/DocsExamples/Utilities/CircuitBreakerDocSpec.cs index ee416ade524..f1a7ca82797 100644 --- a/docs/examples/Utilities/CircuitBreakers/DangerousActor.cs +++ b/docs/examples/DocsExamples/Utilities/CircuitBreakerDocSpec.cs @@ -6,11 +6,33 @@ namespace DocsExamples.Utilities.CircuitBreakers { + #region circuit-breaker-usage public class DangerousActor : ReceiveActor { private readonly ILoggingAdapter _log = Context.GetLogger(); public DangerousActor() + { + var breaker = new CircuitBreaker( + maxFailures: 5, + callTimeout: TimeSpan.FromSeconds(10), + resetTimeout: TimeSpan.FromMinutes(1)) + .OnOpen(NotifyMeOnOpen); + } + + private void NotifyMeOnOpen() + { + _log.Warning("My CircuitBreaker is now open, and will not close for one minute"); + } + } + #endregion + + #region call-protection + public class DangerousActorCallProtection : ReceiveActor + { + private readonly ILoggingAdapter _log = Context.GetLogger(); + + public DangerousActorCallProtection() { var breaker = new CircuitBreaker( maxFailures: 5, @@ -36,4 +58,5 @@ private void NotifyMeOnOpen() _log.Warning("My CircuitBreaker is now open, and will not close for one minute"); } } + #endregion } diff --git a/docs/examples/Persistence/PersistentFSM/ExamplePersistentFSM.cs b/docs/examples/Persistence/PersistentFSM/ExamplePersistentFSM.cs deleted file mode 100644 index f0d84c663d6..00000000000 --- a/docs/examples/Persistence/PersistentFSM/ExamplePersistentFSM.cs +++ /dev/null @@ -1,134 +0,0 @@ -using System; -using Akka.Persistence.Fsm; -using Akka.Actor; - -namespace DocsExamples.Persistence.PersistentFSM -{ - public class ExamplePersistentFSM : PersistentFSM - { - private readonly IActorRef _reportActor; - - public ExamplePersistentFSM(string persistenceId, IActorRef reportActor) - { - PersistenceId = persistenceId; - _reportActor = reportActor; - - StartWith(UserState.LookingAround, new EmptyShoppingCart()); - - When(UserState.LookingAround, (e, state) => - { - if (e.FsmEvent is AddItem addItem) - { - return GoTo(UserState.Shopping) - .Applying(new ItemAdded(addItem.Item)) - .ForMax(TimeSpan.FromSeconds(1)); - } - - if (e.FsmEvent is GetCurrentCart) - { - return Stay().Replying(e.StateData); - } - - return state; - }); - - When(UserState.Shopping, (e, state) => - { - if (e.FsmEvent is AddItem addItem) - { - return Stay() - .Applying(new ItemAdded(addItem.Item)) - .ForMax(TimeSpan.FromSeconds(1)); - } - - if (e.FsmEvent is Buy) - { - return GoTo(UserState.Paid) - .Applying(new OrderExecuted()) - .AndThen(cart => - { - if (cart is NonEmptyShoppingCart) - { - _reportActor.Tell(new PurchaseWasMade()); - } - }); - } - - if (e.FsmEvent is Leave) - { - return Stop() - .Applying(new OrderDiscarded()) - .AndThen(cart => _reportActor.Tell(new ShoppingCardDiscarded())); - } - - if (e.FsmEvent is GetCurrentCart) - { - return Stay().Replying(e.StateData); - } - - if (e.FsmEvent is StateTimeout) - { - return GoTo(UserState.Inactive).ForMax(TimeSpan.FromSeconds(2)); - } - - return state; - }); - - When(UserState.Inactive, (e, state) => - { - if (e.FsmEvent is AddItem addItem) - { - return GoTo(UserState.Shopping) - .Applying(new ItemAdded(addItem.Item)) - .ForMax(TimeSpan.FromSeconds(1)); - } - - if (e.FsmEvent is GetCurrentCart) - { - return Stop() - .Applying(new OrderDiscarded()) - .AndThen(cart => _reportActor.Tell(new ShoppingCardDiscarded())); - } - - return state; - }); - - When(UserState.Paid, (e, state) => - { - if (e.FsmEvent is Leave) - { - return Stop(); - } - - if (e.FsmEvent is GetCurrentCart) - { - return Stay().Replying(e.StateData); - } - - return state; - }); - } - - protected override IShoppingCart ApplyEvent(IDomainEvent e, IShoppingCart data) - { - switch (e) - { - case ItemAdded itemAdded: - return data.AddItem(itemAdded.Item); - case OrderExecuted orderedExecuted: - return data; - case OrderDiscarded orderDiscarded: - return data.Empty(); - default: - return data; - } - } - - protected override void OnRecoveryCompleted() - { - - } - - public override string PersistenceId { get; } - } -} diff --git a/docs/examples/Persistence/PersistentFSM/PersistentFSM.Commands.cs b/docs/examples/Persistence/PersistentFSM/PersistentFSM.Commands.cs deleted file mode 100644 index 134d9c37880..00000000000 --- a/docs/examples/Persistence/PersistentFSM/PersistentFSM.Commands.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace DocsExamples.Persistence.PersistentFSM -{ - public interface ICommand - { - } - - public class AddItem : ICommand - { - public AddItem(Item item) - { - Item = item; - } - - public Item Item { get; set; } - } - - public class Buy : ICommand - { - } - - public class Leave : ICommand - { - } - - public class GetCurrentCart : ICommand - { - } -} diff --git a/docs/examples/Persistence/PersistentFSM/PersistentFSM.Events.cs b/docs/examples/Persistence/PersistentFSM/PersistentFSM.Events.cs deleted file mode 100644 index f57ed3573d1..00000000000 --- a/docs/examples/Persistence/PersistentFSM/PersistentFSM.Events.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace DocsExamples.Persistence.PersistentFSM -{ - public interface IDomainEvent - { - } - - public class ItemAdded : IDomainEvent - { - public ItemAdded(Item item) - { - Item = item; - } - - public Item Item { get; set; } - } - - public class OrderExecuted : IDomainEvent - { - } - - public class OrderDiscarded : IDomainEvent - { - } -} diff --git a/docs/examples/Persistence/PersistentFSM/PersistentFSM.Messages.cs b/docs/examples/Persistence/PersistentFSM/PersistentFSM.Messages.cs deleted file mode 100644 index ff0996f14ad..00000000000 --- a/docs/examples/Persistence/PersistentFSM/PersistentFSM.Messages.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Collections.Generic; - -namespace DocsExamples.Persistence.PersistentFSM -{ - public class Item - { - public Item(string id, string name, double price) - { - Id = id; - Name = name; - Price = price; - } - - public string Id { get; set; } - - public string Name { get; set; } - - public double Price { get; set; } - } - - public interface IShoppingCart - { - ICollection Items { get; set; } - - IShoppingCart AddItem(Item item); - - IShoppingCart Empty(); - } - - public class EmptyShoppingCart : IShoppingCart - { - public IShoppingCart AddItem(Item item) - { - return new NonEmptyShoppingCart(item); - } - - public IShoppingCart Empty() - { - return this; - } - - public ICollection Items { get; set; } - } - - public class NonEmptyShoppingCart : IShoppingCart - { - public NonEmptyShoppingCart(Item item) - { - Items = new List(); - Items.Add(item); - } - - public IShoppingCart AddItem(Item item) - { - Items.Add(item); - return this; - } - - public IShoppingCart Empty() - { - return new EmptyShoppingCart(); - } - - public ICollection Items { get; set; } - } -} diff --git a/docs/examples/Persistence/PersistentFSM/PersistentFSM.SideEffects.cs b/docs/examples/Persistence/PersistentFSM/PersistentFSM.SideEffects.cs deleted file mode 100644 index b766430a0f8..00000000000 --- a/docs/examples/Persistence/PersistentFSM/PersistentFSM.SideEffects.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace DocsExamples.Persistence.PersistentFSM -{ - internal interface IReportEvent - { - } - - internal class PurchaseWasMade : IReportEvent - { - } - - internal class ShoppingCardDiscarded : IReportEvent - { - } -} diff --git a/docs/examples/Persistence/PersistentFSM/PersistentFSM.State.cs b/docs/examples/Persistence/PersistentFSM/PersistentFSM.State.cs deleted file mode 100644 index fbd338ab5ea..00000000000 --- a/docs/examples/Persistence/PersistentFSM/PersistentFSM.State.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace DocsExamples.Persistence.PersistentFSM -{ - public enum UserState - { - Shopping, - Inactive, - Paid, - LookingAround - } -} diff --git a/docs/examples/Tutorials/Program.cs b/docs/examples/Tutorials/Program.cs new file mode 100644 index 00000000000..f1300d03253 --- /dev/null +++ b/docs/examples/Tutorials/Program.cs @@ -0,0 +1,14 @@ +using System; +using Akka.Actor; +using Tutorials.Tutorial1; + +namespace DocsExamples +{ + class Program + { + static void Main(string[] args) + { + IotApp.Init(); + } + } +} \ No newline at end of file diff --git a/docs/examples/Tutorials/Tutorial1/ActorHierarchyExperiments.cs b/docs/examples/Tutorials/Tutorial1/ActorHierarchyExperiments.cs new file mode 100644 index 00000000000..37b7dfa594f --- /dev/null +++ b/docs/examples/Tutorials/Tutorial1/ActorHierarchyExperiments.cs @@ -0,0 +1,121 @@ +using System; +using System.Runtime.Remoting.Contexts; +using Akka.Actor; +using Akka.TestKit.Xunit2; +using Xunit; + +namespace Tutorials.Tutorial1 +{ + #region print-refs + public class PrintMyActorRefActor : UntypedActor + { + protected override void OnReceive(object message) + { + switch (message) + { + case "printit": + IActorRef secondRef = Context.ActorOf(Props.Empty, "second-actor"); + Console.WriteLine($"Second: {secondRef}"); + break; + } + } + } + #endregion + + #region start-stop + public class StartStopActor1 : UntypedActor + { + protected override void PreStart() + { + Console.WriteLine("first started"); + Context.ActorOf(Props.Create(), "second"); + } + + protected override void PostStop() => Console.WriteLine("first stopped"); + + protected override void OnReceive(object message) + { + switch (message) + { + case "stop": + Context.Stop(Self); + break; + } + } + } + + public class StartStopActor2 : UntypedActor + { + protected override void PreStart() => Console.WriteLine("second started"); + protected override void PostStop() => Console.WriteLine("second stopped"); + + protected override void OnReceive(object message) + { + } + } + #endregion + + #region supervise + public class SupervisingActor : UntypedActor + { + private IActorRef child = Context.ActorOf(Props.Create(), "supervised-actor"); + + protected override void OnReceive(object message) + { + switch (message) + { + case "failChild": + child.Tell("fail"); + break; + } + } + } + + public class SupervisedActor : UntypedActor + { + protected override void PreStart() => Console.WriteLine("supervised actor started"); + protected override void PostStop() => Console.WriteLine("supervised actor stopped"); + + protected override void OnReceive(object message) + { + switch (message) + { + case "fail": + Console.WriteLine("supervised actor fails now"); + throw new Exception("I failed!"); + } + } + } + #endregion + + public class ActorHierarchyExperiments : TestKit + { + [Fact] + public void Create_top_and_child_actor() + { + #region print-refs2 + var firstRef = Sys.ActorOf(Props.Create(), "first-actor"); + Console.WriteLine($"First: {firstRef}"); + firstRef.Tell("printit", ActorRefs.NoSender); + #endregion + } + + [Fact] + public void Start_and_stop_actors() + { + #region start-stop2 + var first = Sys.ActorOf(Props.Create(), "first"); + first.Tell("stop"); + #endregion + } + + [Fact] + public void Supervise_actors() + { + #region supervise2 + var supervisingActor = Sys.ActorOf(Props.Create(), "supervising-actor"); + supervisingActor.Tell("failChild"); + #endregion + } + } +} diff --git a/docs/examples/Tutorials/Tutorial1/IotApp.cs b/docs/examples/Tutorials/Tutorial1/IotApp.cs new file mode 100644 index 00000000000..ac595dd626e --- /dev/null +++ b/docs/examples/Tutorials/Tutorial1/IotApp.cs @@ -0,0 +1,21 @@ +using System; +using Akka.Actor; + +namespace Tutorials.Tutorial1 +{ + #region iot-app + public class IotApp + { + public static void Init() + { + using (var system = ActorSystem.Create("iot-system")) + { + // Create top level supervisor + var supervisor = system.ActorOf(Props.Create(), "iot-supervisor"); + // Exit the system after ENTER is pressed + Console.ReadLine(); + } + } + } + #endregion +} diff --git a/docs/examples/Tutorials/Tutorial1/IotSupervisor.cs b/docs/examples/Tutorials/Tutorial1/IotSupervisor.cs new file mode 100644 index 00000000000..316f35b18b5 --- /dev/null +++ b/docs/examples/Tutorials/Tutorial1/IotSupervisor.cs @@ -0,0 +1,23 @@ +using System; +using Akka.Actor; +using Akka.Event; + +namespace Tutorials.Tutorial1 +{ + #region iot-supervisor + public class IotSupervisor : UntypedActor + { + public ILoggingAdapter Log { get; } = Context.GetLogger(); + + protected override void PreStart() => Log.Info("IoT Application started"); + protected override void PostStop() => Log.Info("IoT Application stopped"); + + // No need to handle any messages + protected override void OnReceive(object message) + { + } + + public static Props Props() => Akka.Actor.Props.Create(); + } + #endregion +} diff --git a/docs/examples/Tutorials/Tutorial2/Device.cs b/docs/examples/Tutorials/Tutorial2/Device.cs new file mode 100644 index 00000000000..1cffbf9ad26 --- /dev/null +++ b/docs/examples/Tutorials/Tutorial2/Device.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Akka.Actor; +using Akka.Event; + +namespace Tutorials.Tutorial2 +{ + public static class MainDevice + { + #region full-device + public sealed class RecordTemperature + { + public RecordTemperature(long requestId, double value) + { + RequestId = requestId; + Value = value; + } + + public long RequestId { get; } + public double Value { get; } + } + + public sealed class TemperatureRecorded + { + public TemperatureRecorded(long requestId) + { + RequestId = requestId; + } + + public long RequestId { get; } + } + + public sealed class ReadTemperature + { + public ReadTemperature(long requestId) + { + RequestId = requestId; + } + + public long RequestId { get; } + } + + public sealed class RespondTemperature + { + public RespondTemperature(long requestId, double? value) + { + RequestId = requestId; + Value = value; + } + + public long RequestId { get; } + public double? Value { get; } + } + + public class Device : UntypedActor + { + private double? _lastTemperatureReading = null; + + public Device(string groupId, string deviceId) + { + GroupId = groupId; + DeviceId = deviceId; + } + + protected override void PreStart() => Log.Info($"Device actor {GroupId}-{DeviceId} started"); + protected override void PostStop() => Log.Info($"Device actor {GroupId}-{DeviceId} stopped"); + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + protected string GroupId { get; } + protected string DeviceId { get; } + + protected override void OnReceive(object message) + { + switch (message) + { + case RecordTemperature rec: + Log.Info($"Recorded temperature reading {rec.Value} with {rec.RequestId}"); + _lastTemperatureReading = rec.Value; + Sender.Tell(new TemperatureRecorded(rec.RequestId)); + break; + case ReadTemperature read: + Sender.Tell(new RespondTemperature(read.RequestId, _lastTemperatureReading)); + break; + } + } + + public static Props Props(string groupId, string deviceId) => + Akka.Actor.Props.Create(() => new Device(groupId, deviceId)); + } + + #endregion + } +} diff --git a/docs/examples/Tutorials/Tutorial2/DeviceInProgress.cs b/docs/examples/Tutorials/Tutorial2/DeviceInProgress.cs new file mode 100644 index 00000000000..4500f909724 --- /dev/null +++ b/docs/examples/Tutorials/Tutorial2/DeviceInProgress.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Akka.Actor; +using Akka.Event; + +namespace Tutorials.Tutorial2 +{ + public static class DeviceInProgress1 + { + #region read-protocol-1 + public sealed class ReadTemperature + { + public static ReadTemperature Instance { get; } = new ReadTemperature(); + private ReadTemperature() { } + } + + public sealed class RespondTemperature + { + public RespondTemperature(double? value) + { + Value = value; + } + + public double? Value { get; } + } + #endregion + } + + public static class DeviceInProgress2 + { + #region read-protocol-2 + public sealed class ReadTemperature + { + public ReadTemperature(long requestId) + { + RequestId = requestId; + } + + public long RequestId { get; } + } + + public sealed class RespondTemperature + { + public RespondTemperature(long requestId, double? value) + { + RequestId = requestId; + Value = value; + } + + public long RequestId { get; } + public double? Value { get; } + } + #endregion + + #region device-with-read + public class Device : UntypedActor + { + private readonly double? _lastTemperatureReading = null; + + public Device(string groupId, string deviceId) + { + GroupId = groupId; + DeviceId = deviceId; + } + + protected override void PreStart() => Log.Info($"Device actor {GroupId}-{DeviceId} started"); + protected override void PostStop() => Log.Info($"Device actor {GroupId}-{DeviceId} stopped"); + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + protected string GroupId { get; } + protected string DeviceId { get; } + + protected override void OnReceive(object message) + { + switch (message) + { + case MainDevice.ReadTemperature read: + Sender.Tell(new RespondTemperature(read.RequestId, _lastTemperatureReading)); + break; + } + } + + public static Props Props(string groupId, string deviceId) => + Akka.Actor.Props.Create(() => new Device(groupId, deviceId)); + } + #endregion + } + + public static class DeviceInProgress3 + { + #region write-protocol-1 + public sealed class RecordTemperature + { + public RecordTemperature(double value) + { + Value = value; + } + + public double Value { get; } + } + #endregion + } +} diff --git a/docs/examples/Tutorials/Tutorial2/DeviceSpec.cs b/docs/examples/Tutorials/Tutorial2/DeviceSpec.cs new file mode 100644 index 00000000000..f6f168f473f --- /dev/null +++ b/docs/examples/Tutorials/Tutorial2/DeviceSpec.cs @@ -0,0 +1,49 @@ +using Akka.TestKit.Xunit2; +using FluentAssertions; +using Xunit; +using static Tutorials.Tutorial2.MainDevice; + +namespace Tutorials.Tutorial2 +{ + public class DeviceSpec : TestKit + { + #region device-read-test + [Fact] + public void Device_actor_must_reply_with_empty_reading_if_no_temperature_is_known() + { + var probe = CreateTestProbe(); + var deviceActor = Sys.ActorOf(Device.Props("group", "device")); + + deviceActor.Tell(new ReadTemperature(requestId: 42), probe.Ref); + var response = probe.ExpectMsg(); + response.RequestId.Should().Be(42); + response.Value.Should().BeNull(); + } + #endregion + + #region device-write-read-test + [Fact] + public void Device_actor_must_reply_with_latest_temperature_reading() + { + var probe = CreateTestProbe(); + var deviceActor = Sys.ActorOf(Device.Props("group", "device")); + + deviceActor.Tell(new RecordTemperature(requestId: 1, value: 24.0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 1); + + deviceActor.Tell(new ReadTemperature(requestId: 2), probe.Ref); + var response1 = probe.ExpectMsg(); + response1.RequestId.Should().Be(2); + response1.Value.Should().Be(24.0); + + deviceActor.Tell(new RecordTemperature(requestId: 3, value: 55.0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 3); + + deviceActor.Tell(new ReadTemperature(requestId: 4), probe.Ref); + var response2 = probe.ExpectMsg(); + response2.RequestId.Should().Be(4); + response2.Value.Should().Be(55.0); + } + #endregion + } +} diff --git a/docs/examples/Tutorials/Tutorial3/Device.cs b/docs/examples/Tutorials/Tutorial3/Device.cs new file mode 100644 index 00000000000..569bc307e0d --- /dev/null +++ b/docs/examples/Tutorials/Tutorial3/Device.cs @@ -0,0 +1,95 @@ +using Akka.Actor; +using Akka.Event; + +namespace Tutorials.Tutorial3 +{ + public static partial class MainDeviceGroup + { + #region device-with-register + public sealed class RecordTemperature + { + public RecordTemperature(long requestId, double value) + { + RequestId = requestId; + Value = value; + } + + public long RequestId { get; } + public double Value { get; } + } + + public sealed class TemperatureRecorded + { + public TemperatureRecorded(long requestId) + { + RequestId = requestId; + } + + public long RequestId { get; } + } + + public sealed class ReadTemperature + { + public ReadTemperature(long requestId) + { + RequestId = requestId; + } + + public long RequestId { get; } + } + + public sealed class RespondTemperature + { + public RespondTemperature(long requestId, double? value) + { + RequestId = requestId; + Value = value; + } + + public long RequestId { get; } + public double? Value { get; } + } + + public class Device : UntypedActor + { + private double? _lastTemperatureReading = null; + + public Device(string groupId, string deviceId) + { + GroupId = groupId; + DeviceId = deviceId; + } + + protected override void PreStart() => Log.Info($"Device actor {GroupId}-{DeviceId} started"); + protected override void PostStop() => Log.Info($"Device actor {GroupId}-{DeviceId} stopped"); + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + protected string GroupId { get; } + protected string DeviceId { get; } + + protected override void OnReceive(object message) + { + switch (message) + { + case RequestTrackDevice req when req.GroupId.Equals("groupId") && req.DeviceId.Equals("deviceId"): + Sender.Tell(DeviceRegistered.Instance); + break; + case RequestTrackDevice req: + Log.Warning($"Ignoring TrackDevice request for {req.GroupId}-{req.DeviceId}.This actor is responsible for {GroupId}-{DeviceId}."); + break; + case RecordTemperature rec: + Log.Info($"Recorded temperature reading {rec.Value} with {rec.RequestId}"); + _lastTemperatureReading = rec.Value; + Sender.Tell(new TemperatureRecorded(rec.RequestId)); + break; + case ReadTemperature read: + Sender.Tell(new RespondTemperature(read.RequestId, _lastTemperatureReading)); + break; + } + } + + public static Props Props(string groupId, string deviceId) => Akka.Actor.Props.Create(() => new Device(groupId, deviceId)); + } + #endregion + } +} diff --git a/docs/examples/Tutorials/Tutorial3/DeviceGroup.cs b/docs/examples/Tutorials/Tutorial3/DeviceGroup.cs new file mode 100644 index 00000000000..56126e47c83 --- /dev/null +++ b/docs/examples/Tutorials/Tutorial3/DeviceGroup.cs @@ -0,0 +1,86 @@ +using System.Collections.Generic; +using Akka.Actor; +using Akka.Event; + +namespace Tutorials.Tutorial3 +{ + public static partial class MainDeviceGroup + { + #region device-group-full + public sealed class RequestDeviceList + { + public RequestDeviceList(long requestId) + { + RequestId = requestId; + } + + public long RequestId { get; } + } + + public sealed class ReplyDeviceList + { + public ReplyDeviceList(long requestId, ISet ids) + { + RequestId = requestId; + Ids = ids; + } + + public long RequestId { get; } + public ISet Ids { get; } + } + + public class DeviceGroup : UntypedActor + { + private Dictionary deviceIdToActor = new Dictionary(); + private Dictionary actorToDeviceId = new Dictionary(); + + public DeviceGroup(string groupId) + { + GroupId = groupId; + } + + protected override void PreStart() => Log.Info($"Device group {GroupId} started"); + protected override void PostStop() => Log.Info($"Device group {GroupId} stopped"); + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + protected string GroupId { get; } + + protected override void OnReceive(object message) + { + switch (message) + { + case RequestTrackDevice trackMsg when trackMsg.GroupId.Equals("groupId"): + if (deviceIdToActor.TryGetValue(trackMsg.DeviceId, out var actorRef)) + { + actorRef.Forward(trackMsg); + } + else + { + Log.Info($"Creating device actor for {trackMsg.DeviceId}"); + var deviceActor = Context.ActorOf(Device.Props(trackMsg.GroupId, trackMsg.DeviceId), $"device-{trackMsg.DeviceId}"); + Context.Watch(deviceActor); + actorToDeviceId.Add(deviceActor, trackMsg.DeviceId); + deviceIdToActor.Add(trackMsg.DeviceId, deviceActor); + deviceActor.Forward(trackMsg); + } + break; + case RequestTrackDevice trackMsg: + Log.Warning($"Ignoring TrackDevice request for {trackMsg.GroupId}. This actor is responsible for {GroupId}."); + break; + case RequestDeviceList deviceList: + Sender.Tell(new ReplyDeviceList(deviceList.RequestId, new HashSet(deviceIdToActor.Keys))); + break; + case Terminated t: + var deviceId = actorToDeviceId[t.ActorRef]; + Log.Info($"Device actor for {deviceId} has been terminated"); + actorToDeviceId.Remove(t.ActorRef); + deviceIdToActor.Remove(deviceId); + break; + } + } + + public static Props Props(string groupId) => Akka.Actor.Props.Create(() => new DeviceGroup(groupId)); + } + #endregion + } +} diff --git a/docs/examples/Tutorials/Tutorial3/DeviceGroupInProgress.cs b/docs/examples/Tutorials/Tutorial3/DeviceGroupInProgress.cs new file mode 100644 index 00000000000..8f61f7f354a --- /dev/null +++ b/docs/examples/Tutorials/Tutorial3/DeviceGroupInProgress.cs @@ -0,0 +1,108 @@ +using System.Collections.Generic; +using Akka.Actor; +using Akka.Event; +using static Tutorials.Tutorial3.MainDeviceGroup; + +namespace Tutorials.Tutorial3 +{ + public static class DeviceGroupInProgress + { + #region device-group-register + public class DeviceGroup : UntypedActor + { + private Dictionary deviceIdToActor = new Dictionary(); + + public DeviceGroup(string groupId) + { + GroupId = groupId; + } + + protected override void PreStart() => Log.Info($"Device group {GroupId} started"); + protected override void PostStop() => Log.Info($"Device group {GroupId} stopped"); + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + protected string GroupId { get; } + + protected override void OnReceive(object message) + { + switch (message) + { + case RequestTrackDevice trackMsg when trackMsg.GroupId.Equals("groupId"): + if (deviceIdToActor.TryGetValue(trackMsg.DeviceId, out var actorRef)) + { + actorRef.Forward(trackMsg); + } + else + { + Log.Info($"Creating device actor for {trackMsg.DeviceId}"); + var deviceActor = Context.ActorOf(Device.Props(trackMsg.GroupId, trackMsg.DeviceId), $"device-{trackMsg.DeviceId}"); + deviceIdToActor.Add(trackMsg.DeviceId, deviceActor); + deviceActor.Forward(trackMsg); + } + break; + case RequestTrackDevice trackMsg: + Log.Warning($"Ignoring TrackDevice request for {trackMsg.GroupId}. This actor is responsible for {GroupId}."); + break; + } + } + + public static Props Props(string groupId) => Akka.Actor.Props.Create(() => new DeviceGroup(groupId)); + } + #endregion + } + + public static class DeviceGroupInProgress2 + { + #region device-group-remove + public class DeviceGroup : UntypedActor + { + private Dictionary deviceIdToActor = new Dictionary(); + private Dictionary actorToDeviceId = new Dictionary(); + + public DeviceGroup(string groupId) + { + GroupId = groupId; + } + + protected override void PreStart() => Log.Info($"Device group {GroupId} started"); + protected override void PostStop() => Log.Info($"Device group {GroupId} stopped"); + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + protected string GroupId { get; } + + protected override void OnReceive(object message) + { + switch (message) + { + case RequestTrackDevice trackMsg when trackMsg.GroupId.Equals("groupId"): + if (deviceIdToActor.TryGetValue(trackMsg.DeviceId, out var actorRef)) + { + actorRef.Forward(trackMsg); + } + else + { + Log.Info($"Creating device actor for {trackMsg.DeviceId}"); + var deviceActor = Context.ActorOf(Device.Props(trackMsg.GroupId, trackMsg.DeviceId), $"device-{trackMsg.DeviceId}"); + Context.Watch(deviceActor); + actorToDeviceId.Add(deviceActor, trackMsg.DeviceId); + deviceIdToActor.Add(trackMsg.DeviceId, deviceActor); + deviceActor.Forward(trackMsg); + } + break; + case RequestTrackDevice trackMsg: + Log.Warning($"Ignoring TrackDevice request for {trackMsg.GroupId}. This actor is responsible for {GroupId}."); + break; + case Terminated t: + var deviceId = actorToDeviceId[t.ActorRef]; + Log.Info($"Device actor for {deviceId} has been terminated"); + actorToDeviceId.Remove(t.ActorRef); + deviceIdToActor.Remove(deviceId); + break; + } + } + + public static Props Props(string groupId) => Akka.Actor.Props.Create(() => new DeviceGroup(groupId)); + } + #endregion + } +} diff --git a/docs/examples/Tutorials/Tutorial3/DeviceGroupSpec.cs b/docs/examples/Tutorials/Tutorial3/DeviceGroupSpec.cs new file mode 100644 index 00000000000..88f330bd089 --- /dev/null +++ b/docs/examples/Tutorials/Tutorial3/DeviceGroupSpec.cs @@ -0,0 +1,118 @@ +using System; +using Akka.Actor; +using Akka.TestKit.Xunit2; +using FluentAssertions; +using Xunit; + +namespace Tutorials.Tutorial3 +{ + public static partial class MainDeviceGroup + { + public class DeviceGroupSpec : TestKit + { + #region device-group-test-registration + [Fact] + public void DeviceGroup_actor_must_be_able_to_register_a_device_actor() + { + var probe = CreateTestProbe(); + var groupActor = Sys.ActorOf(DeviceGroup.Props("group")); + + groupActor.Tell(new RequestTrackDevice("group", "device1"), probe.Ref); + probe.ExpectMsg(); + var deviceActor1 = probe.LastSender; + + groupActor.Tell(new RequestTrackDevice("group", "device2"), probe.Ref); + probe.ExpectMsg(); + var deviceActor2 = probe.LastSender; + deviceActor1.Should().NotBe(deviceActor2); + + // Check that the device actors are working + deviceActor1.Tell(new RecordTemperature(requestId: 0, value: 1.0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 0); + deviceActor2.Tell(new RecordTemperature(requestId: 1, value: 2.0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 1); + } + + [Fact] + public void DeviceGroup_actor_must_ignore_requests_for_wrong_groupId() + { + var probe = CreateTestProbe(); + var groupActor = Sys.ActorOf(DeviceGroup.Props("group")); + + groupActor.Tell(new RequestTrackDevice("wrongGroup", "device1"), probe.Ref); + probe.ExpectNoMsg(TimeSpan.FromMilliseconds(500)); + } + #endregion + + #region device-group-test3 + [Fact] + public void DeviceGroup_actor_must_return_same_actor_for_same_deviceId() + { + var probe = CreateTestProbe(); + var groupActor = Sys.ActorOf(DeviceGroup.Props("group")); + + groupActor.Tell(new RequestTrackDevice("group", "device1"), probe.Ref); + probe.ExpectMsg(); + var deviceActor1 = probe.LastSender; + + groupActor.Tell(new RequestTrackDevice("group", "device1"), probe.Ref); + probe.ExpectMsg(); + var deviceActor2 = probe.LastSender; + + deviceActor1.Should().Be(deviceActor2); + } + #endregion + + #region device-group-list-terminate-test + [Fact] + public void DeviceGroup_actor_must_be_able_to_list_active_devices() + { + var probe = CreateTestProbe(); + var groupActor = Sys.ActorOf(DeviceGroup.Props("group")); + + groupActor.Tell(new RequestTrackDevice("group", "device1"), probe.Ref); + probe.ExpectMsg(); + + groupActor.Tell(new RequestTrackDevice("group", "device2"), probe.Ref); + probe.ExpectMsg(); + + groupActor.Tell(new RequestDeviceList(requestId: 0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 0 + && s.Ids.Contains("device1") + && s.Ids.Contains("device2")); + } + + [Fact] + public void DeviceGroup_actor_must_be_able_to_list_active_devices_after_one_shuts_down() + { + var probe = CreateTestProbe(); + var groupActor = Sys.ActorOf(DeviceGroup.Props("group")); + + groupActor.Tell(new RequestTrackDevice("group", "device1"), probe.Ref); + probe.ExpectMsg(); + var toShutDown = probe.LastSender; + + groupActor.Tell(new RequestTrackDevice("group", "device2"), probe.Ref); + probe.ExpectMsg(); + + groupActor.Tell(new RequestDeviceList(requestId: 0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 0 + && s.Ids.Contains("device1") + && s.Ids.Contains("device2")); + + probe.Watch(toShutDown); + toShutDown.Tell(PoisonPill.Instance); + probe.ExpectTerminated(toShutDown); + + // using awaitAssert to retry because it might take longer for the groupActor + // to see the Terminated, that order is undefined + probe.AwaitAssert(() => + { + groupActor.Tell(new RequestDeviceList(requestId: 1), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 1 && s.Ids.Contains("device2")); + }); + } + #endregion + } + } +} diff --git a/docs/examples/Tutorials/Tutorial3/DeviceManager.cs b/docs/examples/Tutorials/Tutorial3/DeviceManager.cs new file mode 100644 index 00000000000..7f5774cfcb6 --- /dev/null +++ b/docs/examples/Tutorials/Tutorial3/DeviceManager.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using Akka.Actor; +using Akka.Event; + +namespace Tutorials.Tutorial3 +{ + #region device-manager-full + public static partial class MainDeviceGroup + { + #region device-manager-msgs + public sealed class RequestTrackDevice + { + public RequestTrackDevice(string groupId, string deviceId) + { + GroupId = groupId; + DeviceId = deviceId; + } + + public string GroupId { get; } + public string DeviceId { get; } + } + + public sealed class DeviceRegistered + { + public static DeviceRegistered Instance { get; } = new DeviceRegistered(); + private DeviceRegistered() { } + } + #endregion + + public class DeviceManager : UntypedActor + { + private Dictionary groupIdToActor = new Dictionary(); + private Dictionary actorToGroupId = new Dictionary(); + + protected override void PreStart() => Log.Info("DeviceManager started"); + protected override void PostStop() => Log.Info("DeviceManager stopped"); + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + + protected override void OnReceive(object message) + { + switch (message) + { + case RequestTrackDevice trackMsg: + if (groupIdToActor.TryGetValue(trackMsg.GroupId, out var actorRef)) + { + actorRef.Forward(trackMsg); + } + else + { + Log.Info($"Creating device group actor for {trackMsg.GroupId}"); + var groupActor = Context.ActorOf(DeviceGroup.Props(trackMsg.GroupId), $"group-{trackMsg.GroupId}"); + Context.Watch(groupActor); + groupActor.Forward(trackMsg); + groupIdToActor.Add(trackMsg.GroupId, groupActor); + actorToGroupId.Add(groupActor, trackMsg.GroupId); + } + break; + case Terminated t: + var groupId = actorToGroupId[t.ActorRef]; + Log.Info($"Device group actor for {groupId} has been terminated"); + actorToGroupId.Remove(t.ActorRef); + groupIdToActor.Remove(groupId); + break; + } + } + + public static Props Props(string groupId) => Akka.Actor.Props.Create(); + } + } + #endregion +} diff --git a/docs/examples/Tutorials/Tutorial3/DeviceSpec.cs b/docs/examples/Tutorials/Tutorial3/DeviceSpec.cs new file mode 100644 index 00000000000..f80b04b1754 --- /dev/null +++ b/docs/examples/Tutorials/Tutorial3/DeviceSpec.cs @@ -0,0 +1,74 @@ +using System; +using Akka.TestKit.Xunit2; +using FluentAssertions; +using Xunit; + +namespace Tutorials.Tutorial3 +{ + public static partial class MainDeviceGroup + { + public class DeviceSpec : TestKit + { + #region device-registration-tests + [Fact] + public void Device_actor_must_reply_to_registration_requests() + { + var probe = CreateTestProbe(); + var deviceActor = Sys.ActorOf(Device.Props("group", "device")); + + deviceActor.Tell(new RequestTrackDevice("group", "device"), probe.Ref); + probe.ExpectMsg(); + probe.LastSender.Should().Be(deviceActor); + } + + [Fact] + public void Device_actor_must_ignore_wrong_registration_requests() + { + var probe = CreateTestProbe(); + var deviceActor = Sys.ActorOf(Device.Props("group", "device")); + + deviceActor.Tell(new RequestTrackDevice("wrongGroup", "device"), probe.Ref); + probe.ExpectNoMsg(TimeSpan.FromMilliseconds(500)); + + deviceActor.Tell(new RequestTrackDevice("group", "Wrongdevice"), probe.Ref); + probe.ExpectNoMsg(TimeSpan.FromMilliseconds(500)); + } + #endregion + + [Fact] + public void Device_actor_must_reply_with_empty_reading_if_no_temperature_is_known() + { + var probe = CreateTestProbe(); + var deviceActor = Sys.ActorOf(Device.Props("group", "device")); + + deviceActor.Tell(new ReadTemperature(requestId: 42), probe.Ref); + var response = probe.ExpectMsg(); + response.RequestId.Should().Be(42); + response.Value.Should().BeNull(); + } + + [Fact] + public void Device_actor_must_reply_with_latest_temperature_reading() + { + var probe = CreateTestProbe(); + var deviceActor = Sys.ActorOf(Device.Props("group", "device")); + + deviceActor.Tell(new RecordTemperature(requestId: 1, value: 24.0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 1); + + deviceActor.Tell(new ReadTemperature(requestId: 2), probe.Ref); + var response1 = probe.ExpectMsg(); + response1.RequestId.Should().Be(2); + response1.Value.Should().Be(24.0); + + deviceActor.Tell(new RecordTemperature(requestId: 3, value: 55.0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 3); + + deviceActor.Tell(new ReadTemperature(requestId: 4), probe.Ref); + var response2 = probe.ExpectMsg(); + response2.RequestId.Should().Be(4); + response2.Value.Should().Be(55.0); + } + } + } +} diff --git a/docs/examples/Tutorials/Tutorial4/Device.cs b/docs/examples/Tutorials/Tutorial4/Device.cs new file mode 100644 index 00000000000..4aa8276ee55 --- /dev/null +++ b/docs/examples/Tutorials/Tutorial4/Device.cs @@ -0,0 +1,93 @@ +using Akka.Actor; +using Akka.Event; + +namespace Tutorials.Tutorial4 +{ + public static partial class MainDeviceGroup + { + public sealed class RecordTemperature + { + public RecordTemperature(long requestId, double value) + { + RequestId = requestId; + Value = value; + } + + public long RequestId { get; } + public double Value { get; } + } + + public sealed class TemperatureRecorded + { + public TemperatureRecorded(long requestId) + { + RequestId = requestId; + } + + public long RequestId { get; } + } + + public sealed class ReadTemperature + { + public ReadTemperature(long requestId) + { + RequestId = requestId; + } + + public long RequestId { get; } + } + + public sealed class RespondTemperature + { + public RespondTemperature(long requestId, double? value) + { + RequestId = requestId; + Value = value; + } + + public long RequestId { get; } + public double? Value { get; } + } + + public class Device : UntypedActor + { + private double? _lastTemperatureReading = null; + + public Device(string groupId, string deviceId) + { + GroupId = groupId; + DeviceId = deviceId; + } + + protected override void PreStart() => Log.Info($"Device actor {GroupId}-{DeviceId} started"); + protected override void PostStop() => Log.Info($"Device actor {GroupId}-{DeviceId} stopped"); + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + protected string GroupId { get; } + protected string DeviceId { get; } + + protected override void OnReceive(object message) + { + switch (message) + { + case RequestTrackDevice req when req.GroupId.Equals("groupId") && req.DeviceId.Equals("deviceId"): + Sender.Tell(DeviceRegistered.Instance); + break; + case RequestTrackDevice req: + Log.Warning($"Ignoring TrackDevice request for {req.GroupId}-{req.DeviceId}.This actor is responsible for {GroupId}-{DeviceId}."); + break; + case RecordTemperature rec: + Log.Info($"Recorded temperature reading {rec.Value} with {rec.RequestId}"); + _lastTemperatureReading = rec.Value; + Sender.Tell(new TemperatureRecorded(rec.RequestId)); + break; + case ReadTemperature read: + Sender.Tell(new RespondTemperature(read.RequestId, _lastTemperatureReading)); + break; + } + } + + public static Props Props(string groupId, string deviceId) => Akka.Actor.Props.Create(() => new Device(groupId, deviceId)); + } + } +} diff --git a/docs/examples/Tutorials/Tutorial4/DeviceGroup.cs b/docs/examples/Tutorials/Tutorial4/DeviceGroup.cs new file mode 100644 index 00000000000..552296321be --- /dev/null +++ b/docs/examples/Tutorials/Tutorial4/DeviceGroup.cs @@ -0,0 +1,146 @@ +using System; +using System.Collections.Generic; +using Akka.Actor; +using Akka.Event; + +namespace Tutorials.Tutorial4 +{ + public static partial class MainDeviceGroup + { + public sealed class RequestDeviceList + { + public RequestDeviceList(long requestId) + { + RequestId = requestId; + } + + public long RequestId { get; } + } + + public sealed class ReplyDeviceList + { + public ReplyDeviceList(long requestId, ISet ids) + { + RequestId = requestId; + Ids = ids; + } + + public long RequestId { get; } + public ISet Ids { get; } + } + + #region query-protocol + public sealed class RequestAllTemperatures + { + public RequestAllTemperatures(long requestId) + { + RequestId = requestId; + } + + public long RequestId { get; } + } + + public sealed class RespondAllTemperatures + { + public RespondAllTemperatures(long requestId, Dictionary temperatures) + { + RequestId = requestId; + Temperatures = temperatures; + } + + public long RequestId { get; } + public Dictionary Temperatures { get; } + } + + public interface ITemperatureReading + { + } + + public sealed class Temperature : ITemperatureReading + { + public Temperature(double value) + { + Value = value; + } + + public double Value { get; } + } + + public sealed class TemperatureNotAvailable : ITemperatureReading + { + public static TemperatureNotAvailable Instance { get; } = new TemperatureNotAvailable(); + private TemperatureNotAvailable() { } + } + + public sealed class DeviceNotAvailable : ITemperatureReading + { + public static DeviceNotAvailable Instance { get; } = new DeviceNotAvailable(); + private DeviceNotAvailable() { } + } + + public sealed class DeviceTimedOut : ITemperatureReading + { + public static DeviceTimedOut Instance { get; } = new DeviceTimedOut(); + private DeviceTimedOut() { } + } + #endregion + + public class DeviceGroup : UntypedActor + { + private Dictionary deviceIdToActor = new Dictionary(); + private Dictionary actorToDeviceId = new Dictionary(); + private long nextCollectionId = 0L; + + public DeviceGroup(string groupId) + { + GroupId = groupId; + } + + protected override void PreStart() => Log.Info($"Device group {GroupId} started"); + protected override void PostStop() => Log.Info($"Device group {GroupId} stopped"); + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + protected string GroupId { get; } + + protected override void OnReceive(object message) + { + switch (message) + { + case RequestTrackDevice trackMsg when trackMsg.GroupId.Equals("groupId"): + if (deviceIdToActor.TryGetValue(trackMsg.DeviceId, out var actorRef)) + { + actorRef.Forward(trackMsg); + } + else + { + Log.Info($"Creating device actor for {trackMsg.DeviceId}"); + var deviceActor = Context.ActorOf(Device.Props(trackMsg.GroupId, trackMsg.DeviceId), $"device-{trackMsg.DeviceId}"); + Context.Watch(deviceActor); + actorToDeviceId.Add(deviceActor, trackMsg.DeviceId); + deviceIdToActor.Add(trackMsg.DeviceId, deviceActor); + deviceActor.Forward(trackMsg); + } + break; + case RequestTrackDevice trackMsg: + Log.Warning($"Ignoring TrackDevice request for {trackMsg.GroupId}. This actor is responsible for {GroupId}."); + break; + case RequestDeviceList deviceList: + Sender.Tell(new ReplyDeviceList(deviceList.RequestId, new HashSet(deviceIdToActor.Keys))); + break; + case Terminated t: + var deviceId = actorToDeviceId[t.ActorRef]; + Log.Info($"Device actor for {deviceId} has been terminated"); + actorToDeviceId.Remove(t.ActorRef); + deviceIdToActor.Remove(deviceId); + break; + case RequestAllTemperatures r: + Context.ActorOf(DeviceGroupQuery.Props(actorToDeviceId, r.RequestId, Sender, TimeSpan.FromSeconds(3))); + break; + } + } + + public static Props Props(string groupId) => Akka.Actor.Props.Create(() => new DeviceGroup(groupId)); + } + + } +} diff --git a/docs/examples/Tutorials/Tutorial4/DeviceGroupQuery.cs b/docs/examples/Tutorials/Tutorial4/DeviceGroupQuery.cs new file mode 100644 index 00000000000..27b5e4123bd --- /dev/null +++ b/docs/examples/Tutorials/Tutorial4/DeviceGroupQuery.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using Akka.Actor; +using Akka.Event; + +namespace Tutorials.Tutorial4 +{ + public static partial class MainDeviceGroup + { + #region query-full + public sealed class CollectionTimeout + { + public static CollectionTimeout Instance { get; } = new CollectionTimeout(); + private CollectionTimeout() { } + } + + public class DeviceGroupQuery : UntypedActor + { + private ICancelable queryTimeoutTimer; + + public DeviceGroupQuery(Dictionary actorToDeviceId, long requestId, IActorRef requester, TimeSpan timeout) + { + ActorToDeviceId = actorToDeviceId; + RequestId = requestId; + Requester = requester; + Timeout = timeout; + + queryTimeoutTimer = Context.System.Scheduler.ScheduleTellOnceCancelable(timeout, Self, CollectionTimeout.Instance, Self); + } + + protected override void PreStart() + { + foreach (var deviceActor in ActorToDeviceId.Keys) + { + Context.Watch(deviceActor); + deviceActor.Tell(new ReadTemperature(0)); + } + } + + protected override void PostStop() + { + queryTimeoutTimer.Cancel(); + } + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + public Dictionary ActorToDeviceId { get; } + public long RequestId { get; } + public IActorRef Requester { get; } + public TimeSpan Timeout { get; } + + #region query-state + protected override void OnReceive(object message) + { + Become(WaitingForReplies(new Dictionary(), new HashSet(ActorToDeviceId.Keys))); + } + + public UntypedReceive WaitingForReplies( + Dictionary repliesSoFar, + HashSet stillWaiting) + { + return message => + { + switch (message) + { + case RespondTemperature response when response.RequestId == 0: + var deviceActor = Sender; + ITemperatureReading reading = null; + if (response.Value.HasValue) + { + reading = new Temperature(response.Value.Value); + } + else + { + reading = TemperatureNotAvailable.Instance; + } + ReceivedResponse(deviceActor, reading, stillWaiting, repliesSoFar); + break; + case Terminated t: + ReceivedResponse(t.ActorRef, DeviceNotAvailable.Instance, stillWaiting, repliesSoFar); + break; + case CollectionTimeout _: + var replies = new Dictionary(repliesSoFar); + foreach (var actor in stillWaiting) + { + var deviceId = ActorToDeviceId[actor]; + replies.Add(deviceId, DeviceTimedOut.Instance); + } + Requester.Tell(new RespondAllTemperatures(RequestId, replies)); + Context.Stop(Self); + break; + } + }; + } + #endregion + + #region query-collect-reply + public void ReceivedResponse( + IActorRef deviceActor, + ITemperatureReading reading, + HashSet stillWaiting, + Dictionary repliesSoFar) + { + Context.Unwatch(deviceActor); + var deviceId = ActorToDeviceId[deviceActor]; + stillWaiting.Remove(deviceActor); + + repliesSoFar.Add(deviceId, reading); + + if (repliesSoFar.Count == 0) + { + Requester.Tell(new RespondAllTemperatures(RequestId, repliesSoFar)); + Context.Stop(Self); + } + else + { + Context.Become(WaitingForReplies(repliesSoFar, stillWaiting)); + } + } + #endregion + + public static Props Props(Dictionary actorToDeviceId, long requestId, IActorRef requester, TimeSpan timeout) => + Akka.Actor.Props.Create(() => new DeviceGroupQuery(actorToDeviceId, requestId, requester, timeout)); + } + #endregion + } +} diff --git a/docs/examples/Tutorials/Tutorial4/DeviceGroupQueryInProgress.cs b/docs/examples/Tutorials/Tutorial4/DeviceGroupQueryInProgress.cs new file mode 100644 index 00000000000..ce87daf50bd --- /dev/null +++ b/docs/examples/Tutorials/Tutorial4/DeviceGroupQueryInProgress.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using Akka.Actor; +using Akka.Event; +using static Tutorials.Tutorial4.MainDeviceGroup; + +namespace Tutorials.Tutorial4 +{ + public static class DeviceGroupQueryInProgress + { + #region query-outline + public class DeviceGroupQuery : UntypedActor + { + private ICancelable queryTimeoutTimer; + + public DeviceGroupQuery(Dictionary actorToDeviceId, long requestId, IActorRef requester, TimeSpan timeout) + { + ActorToDeviceId = actorToDeviceId; + RequestId = requestId; + Requester = requester; + Timeout = timeout; + + queryTimeoutTimer = Context.System.Scheduler.ScheduleTellOnceCancelable(timeout, Self, CollectionTimeout.Instance, Self); + } + + protected override void PreStart() + { + foreach (var deviceActor in ActorToDeviceId.Keys) + { + Context.Watch(deviceActor); + deviceActor.Tell(new ReadTemperature(0)); + } + } + + protected override void PostStop() + { + queryTimeoutTimer.Cancel(); + } + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + public Dictionary ActorToDeviceId { get; } + public long RequestId { get; } + public IActorRef Requester { get; } + public TimeSpan Timeout { get; } + + protected override void OnReceive(object message) + { + + } + + public static Props Props(Dictionary actorToDeviceId, long requestId, IActorRef requester, TimeSpan timeout) => + Akka.Actor.Props.Create(() => new DeviceGroupQuery(actorToDeviceId, requestId, requester, timeout)); + } + #endregion + } + + public static class DeviceGroupInProgress2 + { + #region query-added + public class DeviceGroup : UntypedActor + { + private Dictionary deviceIdToActor = new Dictionary(); + private Dictionary actorToDeviceId = new Dictionary(); + private long nextCollectionId = 0L; + + public DeviceGroup(string groupId) + { + GroupId = groupId; + } + + protected override void PreStart() => Log.Info($"Device group {GroupId} started"); + protected override void PostStop() => Log.Info($"Device group {GroupId} stopped"); + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + protected string GroupId { get; } + + protected override void OnReceive(object message) + { + switch (message) + { + case RequestAllTemperatures r: + Context.ActorOf(DeviceGroupQuery.Props(actorToDeviceId, r.RequestId, Sender, TimeSpan.FromSeconds(3))); + break; + } + } + + public static Props Props(string groupId) => Akka.Actor.Props.Create(() => new DeviceGroup(groupId)); + } + #endregion + } +} diff --git a/docs/examples/Tutorials/Tutorial4/DeviceGroupQuerySpec.cs b/docs/examples/Tutorials/Tutorial4/DeviceGroupQuerySpec.cs new file mode 100644 index 00000000000..85e4c0f6659 --- /dev/null +++ b/docs/examples/Tutorials/Tutorial4/DeviceGroupQuerySpec.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using Akka.Actor; +using Akka.TestKit.Xunit2; +using Akka.Util.Internal; +using FluentAssertions; +using Xunit; + +namespace Tutorials.Tutorial4 +{ + public static partial class MainDeviceGroup + { + public class DeviceGroupQuerySpec : TestKit + { + #region query-test-normal + [Fact] + public void DeviceGroupQuery_must_return_temperature_value_for_working_devices() + { + var requester = CreateTestProbe(); + + var device1 = CreateTestProbe(); + var device2 = CreateTestProbe(); + + var queryActor = Sys.ActorOf(DeviceGroupQuery.Props( + actorToDeviceId: new Dictionary { [device1.Ref] = "device1", [device2.Ref] = "device2" }, + requestId: 1, + requester: requester.Ref, + timeout: TimeSpan.FromSeconds(3) + )); + + device1.ExpectMsg(read => read.RequestId == 0); + device2.ExpectMsg(read => read.RequestId == 0); + + queryActor.Tell(new RespondTemperature(requestId: 0, value: 1.0), device1.Ref); + queryActor.Tell(new RespondTemperature(requestId: 0, value: 2.0), device2.Ref); + + requester.ExpectMsg(msg => + msg.Temperatures["device1"].AsInstanceOf().Value == 1.0 && + msg.Temperatures["device2"].AsInstanceOf().Value == 2.0 && + msg.RequestId == 1); + } + #endregion + + #region query-test-no-reading + [Fact] + public void DeviceGroupQuery_must_return_TemperatureNotAvailable_for_devices_with_no_readings() + { + var requester = CreateTestProbe(); + + var device1 = CreateTestProbe(); + var device2 = CreateTestProbe(); + + var queryActor = Sys.ActorOf(DeviceGroupQuery.Props( + actorToDeviceId: new Dictionary { [device1.Ref] = "device1", [device2.Ref] = "device2" }, + requestId: 1, + requester: requester.Ref, + timeout: TimeSpan.FromSeconds(3) + )); + + device1.ExpectMsg(read => read.RequestId == 0); + device2.ExpectMsg(read => read.RequestId == 0); + + queryActor.Tell(new RespondTemperature(requestId: 0, value: null), device1.Ref); + queryActor.Tell(new RespondTemperature(requestId: 0, value: 2.0), device2.Ref); + + requester.ExpectMsg(msg => + msg.Temperatures["device1"] is TemperatureNotAvailable && + msg.Temperatures["device2"].AsInstanceOf().Value == 2.0 && + msg.RequestId == 1); + } + #endregion + + #region query-test-stopped + [Fact] + public void DeviceGroupQuery_must_return_return_DeviceNotAvailable_if_device_stops_before_answering() + { + var requester = CreateTestProbe(); + + var device1 = CreateTestProbe(); + var device2 = CreateTestProbe(); + + var queryActor = Sys.ActorOf(DeviceGroupQuery.Props( + actorToDeviceId: new Dictionary { [device1.Ref] = "device1", [device2.Ref] = "device2" }, + requestId: 1, + requester: requester.Ref, + timeout: TimeSpan.FromSeconds(3) + )); + + device1.ExpectMsg(read => read.RequestId == 0); + device2.ExpectMsg(read => read.RequestId == 0); + + queryActor.Tell(new RespondTemperature(requestId: 0, value: 1.0), device2.Ref); + device2.Tell(PoisonPill.Instance); + + requester.ExpectMsg(msg => + msg.Temperatures["device1"].AsInstanceOf().Value == 1.0 && + msg.Temperatures["device2"] is DeviceNotAvailable && + msg.RequestId == 1); + } + #endregion + + #region query-test-stopped-later + [Fact] + public void DeviceGroupQuery_must_return_temperature_reading_even_if_device_stops_after_answering() + { + var requester = CreateTestProbe(); + + var device1 = CreateTestProbe(); + var device2 = CreateTestProbe(); + + var queryActor = Sys.ActorOf(DeviceGroupQuery.Props( + actorToDeviceId: new Dictionary { [device1.Ref] = "device1", [device2.Ref] = "device2" }, + requestId: 1, + requester: requester.Ref, + timeout: TimeSpan.FromSeconds(3) + )); + + device1.ExpectMsg(read => read.RequestId == 0); + device2.ExpectMsg(read => read.RequestId == 0); + + queryActor.Tell(new RespondTemperature(requestId: 0, value: 1.0), device1.Ref); + queryActor.Tell(new RespondTemperature(requestId: 0, value: 2.0), device2.Ref); + device2.Tell(PoisonPill.Instance); + + requester.ExpectMsg(msg => + msg.Temperatures["device1"].AsInstanceOf().Value == 1.0 && + msg.Temperatures["device2"].AsInstanceOf().Value == 2.0 && + msg.RequestId == 1); + } + #endregion + + #region query-test-timeout + [Fact] + public void DeviceGroupQuery_must_return_DeviceTimedOut_if_device_does_not_answer_in_time() + { + var requester = CreateTestProbe(); + + var device1 = CreateTestProbe(); + var device2 = CreateTestProbe(); + + var queryActor = Sys.ActorOf(DeviceGroupQuery.Props( + actorToDeviceId: new Dictionary { [device1.Ref] = "device1", [device2.Ref] = "device2" }, + requestId: 1, + requester: requester.Ref, + timeout: TimeSpan.FromSeconds(1) + )); + + device1.ExpectMsg(read => read.RequestId == 0); + device2.ExpectMsg(read => read.RequestId == 0); + + queryActor.Tell(new RespondTemperature(requestId: 0, value: 1.0), device1.Ref); + + requester.ExpectMsg(msg => + msg.Temperatures["device1"].AsInstanceOf().Value == 1.0 && + msg.Temperatures["device2"] is DeviceTimedOut && + msg.RequestId == 1); + } + #endregion + } + } +} diff --git a/docs/examples/Tutorials/Tutorial4/DeviceGroupSpec.cs b/docs/examples/Tutorials/Tutorial4/DeviceGroupSpec.cs new file mode 100644 index 00000000000..896b6299e9a --- /dev/null +++ b/docs/examples/Tutorials/Tutorial4/DeviceGroupSpec.cs @@ -0,0 +1,147 @@ +using System; +using Akka.Actor; +using Akka.TestKit.Xunit2; +using FluentAssertions; +using Xunit; + +namespace Tutorials.Tutorial4 +{ + public static partial class MainDeviceGroup + { + public class DeviceGroupSpec : TestKit + { + [Fact] + public void DeviceGroup_actor_must_be_able_to_register_a_device_actor() + { + var probe = CreateTestProbe(); + var groupActor = Sys.ActorOf(DeviceGroup.Props("group")); + + groupActor.Tell(new RequestTrackDevice("group", "device1"), probe.Ref); + probe.ExpectMsg(); + var deviceActor1 = probe.LastSender; + + groupActor.Tell(new RequestTrackDevice("group", "device2"), probe.Ref); + probe.ExpectMsg(); + var deviceActor2 = probe.LastSender; + deviceActor1.Should().NotBe(deviceActor2); + + // Check that the device actors are working + deviceActor1.Tell(new RecordTemperature(requestId: 0, value: 1.0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 0); + deviceActor2.Tell(new RecordTemperature(requestId: 1, value: 2.0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 1); + } + + [Fact] + public void DeviceGroup_actor_must_ignore_requests_for_wrong_groupId() + { + var probe = CreateTestProbe(); + var groupActor = Sys.ActorOf(DeviceGroup.Props("group")); + + groupActor.Tell(new RequestTrackDevice("wrongGroup", "device1"), probe.Ref); + probe.ExpectNoMsg(TimeSpan.FromMilliseconds(500)); + } + + [Fact] + public void DeviceGroup_actor_must_return_same_actor_for_same_deviceId() + { + var probe = CreateTestProbe(); + var groupActor = Sys.ActorOf(DeviceGroup.Props("group")); + + groupActor.Tell(new RequestTrackDevice("group", "device1"), probe.Ref); + probe.ExpectMsg(); + var deviceActor1 = probe.LastSender; + + groupActor.Tell(new RequestTrackDevice("group", "device1"), probe.Ref); + probe.ExpectMsg(); + var deviceActor2 = probe.LastSender; + + deviceActor1.Should().Be(deviceActor2); + } + + [Fact] + public void DeviceGroup_actor_must_be_able_to_list_active_devices() + { + var probe = CreateTestProbe(); + var groupActor = Sys.ActorOf(DeviceGroup.Props("group")); + + groupActor.Tell(new RequestTrackDevice("group", "device1"), probe.Ref); + probe.ExpectMsg(); + + groupActor.Tell(new RequestTrackDevice("group", "device2"), probe.Ref); + probe.ExpectMsg(); + + groupActor.Tell(new RequestDeviceList(requestId: 0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 0 + && s.Ids.Contains("device1") + && s.Ids.Contains("device2")); + } + + [Fact] + public void DeviceGroup_actor_must_be_able_to_list_active_devices_after_one_shuts_down() + { + var probe = CreateTestProbe(); + var groupActor = Sys.ActorOf(DeviceGroup.Props("group")); + + groupActor.Tell(new RequestTrackDevice("group", "device1"), probe.Ref); + probe.ExpectMsg(); + var toShutDown = probe.LastSender; + + groupActor.Tell(new RequestTrackDevice("group", "device2"), probe.Ref); + probe.ExpectMsg(); + + groupActor.Tell(new RequestDeviceList(requestId: 0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 0 + && s.Ids.Contains("device1") + && s.Ids.Contains("device2")); + + probe.Watch(toShutDown); + toShutDown.Tell(PoisonPill.Instance); + probe.ExpectTerminated(toShutDown); + + // using awaitAssert to retry because it might take longer for the groupActor + // to see the Terminated, that order is undefined + probe.AwaitAssert(() => + { + groupActor.Tell(new RequestDeviceList(requestId: 1), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 1 && s.Ids.Contains("device2")); + }); + } + + #region group-query-integration-test + [Fact] + public void DeviceGroup_actor_must_be_able_to_collect_temperatures_from_all_active_devices() + { + var probe = CreateTestProbe(); + var groupActor = Sys.ActorOf(DeviceGroup.Props("group")); + + groupActor.Tell(new RequestTrackDevice("group", "device1"), probe.Ref); + probe.ExpectMsg(); + var deviceActor1 = probe.LastSender; + + groupActor.Tell(new RequestTrackDevice("group", "device2"), probe.Ref); + probe.ExpectMsg(); + var deviceActor2 = probe.LastSender; + + groupActor.Tell(new RequestTrackDevice("group", "device3"), probe.Ref); + probe.ExpectMsg(); + var deviceActor3 = probe.LastSender; + + // Check that the device actors are working + deviceActor1.Tell(new RecordTemperature(requestId: 0, value: 1.0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 0); + deviceActor2.Tell(new RecordTemperature(requestId: 1, value: 2.0), probe.Ref); + probe.ExpectMsg(s => s.RequestId == 1); + // No temperature for device3 + + groupActor.Tell(new RequestAllTemperatures(0), probe.Ref); + probe.ExpectMsg(msg => + { + // TODO: compare temperatures dictionary + return msg.RequestId == 0; + }); + } + #endregion + } + } +} diff --git a/docs/examples/Tutorials/Tutorial4/DeviceManager.cs b/docs/examples/Tutorials/Tutorial4/DeviceManager.cs new file mode 100644 index 00000000000..1086f53c42c --- /dev/null +++ b/docs/examples/Tutorials/Tutorial4/DeviceManager.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using Akka.Actor; +using Akka.Event; + +namespace Tutorials.Tutorial4 +{ + public static partial class MainDeviceGroup + { + public sealed class RequestTrackDevice + { + public RequestTrackDevice(string groupId, string deviceId) + { + GroupId = groupId; + DeviceId = deviceId; + } + + public string GroupId { get; } + public string DeviceId { get; } + } + + public sealed class DeviceRegistered + { + public static DeviceRegistered Instance { get; } = new DeviceRegistered(); + private DeviceRegistered() { } + } + + public class DeviceManager : UntypedActor + { + private Dictionary groupIdToActor = new Dictionary(); + private Dictionary actorToGroupId = new Dictionary(); + + protected override void PreStart() => Log.Info("DeviceManager started"); + protected override void PostStop() => Log.Info("DeviceManager stopped"); + + protected ILoggingAdapter Log { get; } = Context.GetLogger(); + + protected override void OnReceive(object message) + { + switch (message) + { + case RequestTrackDevice trackMsg: + if (groupIdToActor.TryGetValue(trackMsg.GroupId, out var actorRef)) + { + actorRef.Forward(trackMsg); + } + else + { + Log.Info($"Creating device group actor for {trackMsg.GroupId}"); + var groupActor = Context.ActorOf(DeviceGroup.Props(trackMsg.GroupId), $"group-{trackMsg.GroupId}"); + Context.Watch(groupActor); + groupActor.Forward(trackMsg); + groupIdToActor.Add(trackMsg.GroupId, groupActor); + actorToGroupId.Add(groupActor, trackMsg.GroupId); + } + break; + case Terminated t: + var groupId = actorToGroupId[t.ActorRef]; + Log.Info($"Device group actor for {groupId} has been terminated"); + actorToGroupId.Remove(t.ActorRef); + groupIdToActor.Remove(groupId); + break; + } + } + + public static Props Props(string groupId) => Akka.Actor.Props.Create(); + } + } +} diff --git a/docs/examples/DocsExamples.csproj b/docs/examples/Tutorials/Tutorials.csproj similarity index 80% rename from docs/examples/DocsExamples.csproj rename to docs/examples/Tutorials/Tutorials.csproj index c8c8e082eb5..c483557d813 100644 --- a/docs/examples/DocsExamples.csproj +++ b/docs/examples/Tutorials/Tutorials.csproj @@ -2,7 +2,7 @@ Exe - net46 + net461 win-x64 @@ -14,12 +14,7 @@ - - - - - - + \ No newline at end of file diff --git a/docs/images/actor_top_tree.png b/docs/images/actor_top_tree.png new file mode 100644 index 00000000000..13f0309ff8f Binary files /dev/null and b/docs/images/actor_top_tree.png differ diff --git a/docs/images/akkalogo.png b/docs/images/akkalogo.png index 8f90d3f4268..0f9cf4eda6a 100644 Binary files a/docs/images/akkalogo.png and b/docs/images/akkalogo.png differ diff --git a/docs/images/arch_boxes_diagram.png b/docs/images/arch_boxes_diagram.png new file mode 100644 index 00000000000..903a1362821 Binary files /dev/null and b/docs/images/arch_boxes_diagram.png differ diff --git a/docs/images/arch_tree_diagram.png b/docs/images/arch_tree_diagram.png new file mode 100644 index 00000000000..979e2c1773d Binary files /dev/null and b/docs/images/arch_tree_diagram.png differ diff --git a/docs/images/device_manager_tree.png b/docs/images/device_manager_tree.png new file mode 100644 index 00000000000..1c02cf0597b Binary files /dev/null and b/docs/images/device_manager_tree.png differ diff --git a/docs/images/favicon.ico b/docs/images/favicon.ico index 56b031d99e8..7ffc333dc85 100644 Binary files a/docs/images/favicon.ico and b/docs/images/favicon.ico differ diff --git a/docs/images/mainlogo.png b/docs/images/mainlogo.png index cb415eadf7e..0f9cf4eda6a 100644 Binary files a/docs/images/mainlogo.png and b/docs/images/mainlogo.png differ diff --git a/docs/index.md b/docs/index.md index 78d59729d8a..417507f0a58 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,16 +10,18 @@ tagline: A straightforward approach to building distributed, high-scale applicat .jumbotron{ text-align: center; } +img.main-logo{ + width: 192px; +} - diff --git a/docs/template/partials/navbar.tmpl.partial b/docs/template/partials/navbar.tmpl.partial index 1f1d8343b9d..e77ce32dcaa 100644 --- a/docs/template/partials/navbar.tmpl.partial +++ b/docs/template/partials/navbar.tmpl.partial @@ -1,3 +1,8 @@ +