From da72e1e4fdfa11f5e5bfec7b25c7b9f4abf88aa5 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Tue, 9 Aug 2016 15:01:57 -0700 Subject: [PATCH 001/210] Project outline for service fabric provider implementation, no classes yet. --- .../DurableTask.ServiceFabric.Test.csproj | 59 ++++++++++++++ .../Properties/AssemblyInfo.cs | 36 +++++++++ .../DurableTask.ServiceFabric.csproj | 77 +++++++++++++++++++ .../Properties/AssemblyInfo.cs | 36 +++++++++ DurableTask.ServiceFabric/packages.config | 5 ++ 5 files changed, 213 insertions(+) create mode 100644 DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj create mode 100644 DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs create mode 100644 DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj create mode 100644 DurableTask.ServiceFabric/Properties/AssemblyInfo.cs create mode 100644 DurableTask.ServiceFabric/packages.config diff --git a/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj b/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj new file mode 100644 index 000000000..98081b9f1 --- /dev/null +++ b/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + {EDC63DDB-8397-4AEC-BF54-6395B2527075} + Library + Properties + DurableTask.ServiceFabric.Test + DurableTask.ServiceFabric.Test + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + {5c617b24-4902-4992-8f71-ab14f00b74a8} + DurableTask.ServiceFabric + + + + + \ No newline at end of file diff --git a/DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs b/DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..61fc9be86 --- /dev/null +++ b/DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DurableTask.ServiceFabric.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DurableTask.ServiceFabric.Test")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("edc63ddb-8397-4aec-bf54-6395b2527075")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj new file mode 100644 index 000000000..914fea431 --- /dev/null +++ b/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -0,0 +1,77 @@ + + + + + Debug + AnyCPU + {5C617B24-4902-4992-8F71-AB14F00B74A8} + Library + Properties + DurableTask.ServiceFabric + DurableTask.ServiceFabric + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll + True + + + ..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll + True + + + ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.dll + True + + + ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll + True + + + + + ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\System.Fabric.dll + True + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs b/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..c2c980c3e --- /dev/null +++ b/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DurableTask.ServiceFabric")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DurableTask.ServiceFabric")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5c617b24-4902-4992-8f71-ab14f00b74a8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DurableTask.ServiceFabric/packages.config b/DurableTask.ServiceFabric/packages.config new file mode 100644 index 000000000..99d0248fb --- /dev/null +++ b/DurableTask.ServiceFabric/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From d7f7dcbf07c85b6a7894bd4b5c7409afca3da5b9 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Tue, 9 Aug 2016 15:08:40 -0700 Subject: [PATCH 002/210] Dummy classes for the minimally required interfaces for a custom provider (no implementation yet). --- .../DurableTask.ServiceFabric.csproj | 8 ++ .../FabricOrchestrationService.cs | 134 ++++++++++++++++++ .../FabricOrchestrationServiceClient.cs | 63 ++++++++ 3 files changed, 205 insertions(+) create mode 100644 DurableTask.ServiceFabric/FabricOrchestrationService.cs create mode 100644 DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs diff --git a/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 914fea431..cb4180b03 100644 --- a/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -61,11 +61,19 @@ + + + + + {6f5d2ead-726d-4fe5-a575-aeb96d1cce37} + DurableTaskFramework + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Cloud.xml b/Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Cloud.xml new file mode 100644 index 000000000..683ffaa5b --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Cloud.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Local.xml b/Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Local.xml new file mode 100644 index 000000000..683ffaa5b --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Local.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Cloud.xml b/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Cloud.xml new file mode 100644 index 000000000..1301dd83f --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Cloud.xml @@ -0,0 +1,25 @@ + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.xml b/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.xml new file mode 100644 index 000000000..c5cffffa3 --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/Scripts/Deploy-FabricApplication.ps1 b/Test/TestFabricApplication/TestFabricApplication/Scripts/Deploy-FabricApplication.ps1 new file mode 100644 index 000000000..f3954db37 --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/Scripts/Deploy-FabricApplication.ps1 @@ -0,0 +1,220 @@ +<# +.SYNOPSIS +Deploys a Service Fabric application type to a cluster. + +.DESCRIPTION +This script deploys a Service Fabric application type to a cluster. It is invoked by Visual Studio when deploying a Service Fabric Application project. + +.NOTES +WARNING: This script file is invoked by Visual Studio. Its parameters must not be altered but its logic can be customized as necessary. + +.PARAMETER PublishProfileFile +Path to the file containing the publish profile. + +.PARAMETER ApplicationPackagePath +Path to the folder of the packaged Service Fabric application. + +.PARAMETER DeloyOnly +Indicates that the Service Fabric application should not be created or upgraded after registering the application type. + +.PARAMETER ApplicationParameter +Hashtable of the Service Fabric application parameters to be used for the application. + +.PARAMETER UnregisterUnusedApplicationVersionsAfterUpgrade +Indicates whether to unregister any unused application versions that exist after an upgrade is finished. + +.PARAMETER OverrideUpgradeBehavior +Indicates the behavior used to override the upgrade settings specified by the publish profile. +'None' indicates that the upgrade settings will not be overriden. +'ForceUpgrade' indicates that an upgrade will occur with default settings, regardless of what is specified in the publish profile. +'VetoUpgrade' indicates that an upgrade will not occur, regardless of what is specified in the publish profile. + +.PARAMETER UseExistingClusterConnection +Indicates that the script should make use of an existing cluster connection that has already been established in the PowerShell session. The cluster connection parameters configured in the publish profile are ignored. + +.PARAMETER OverwriteBehavior +Overwrite Behavior if an application exists in the cluster with the same name. Available Options are Never, Always, SameAppTypeAndVersion. This setting is not applicable when upgrading an application. +'Never' will not remove the existing application. This is the default behavior. +'Always' will remove the existing application even if its Application type and Version is different from the application being created. +'SameAppTypeAndVersion' will remove the existing application only if its Application type and Version is same as the application being created. + +.PARAMETER SkipPackageValidation +Switch signaling whether the package should be validated or not before deployment. + +.PARAMETER SecurityToken +A security token for authentication to cluster management endpoints. Used for silent authentication to clusters that are protected by Azure Active Directory. + +.EXAMPLE +. Scripts\Deploy-FabricApplication.ps1 -ApplicationPackagePath 'pkg\Debug' + +Deploy the application using the default package location for a Debug build. + +.EXAMPLE +. Scripts\Deploy-FabricApplication.ps1 -ApplicationPackagePath 'pkg\Debug' -DoNotCreateApplication + +Deploy the application but do not create the application instance. + +.EXAMPLE +. Scripts\Deploy-FabricApplication.ps1 -ApplicationPackagePath 'pkg\Debug' -ApplicationParameter @{CustomParameter1='MyValue'; CustomParameter2='MyValue'} + +Deploy the application by providing values for parameters that are defined in the application manifest. +#> + +Param +( + [String] + $PublishProfileFile, + + [String] + $ApplicationPackagePath, + + [Switch] + $DeployOnly, + + [Hashtable] + $ApplicationParameter, + + [Boolean] + $UnregisterUnusedApplicationVersionsAfterUpgrade, + + [String] + [ValidateSet('None', 'ForceUpgrade', 'VetoUpgrade')] + $OverrideUpgradeBehavior = 'None', + + [Switch] + $UseExistingClusterConnection, + + [String] + [ValidateSet('Never','Always','SameAppTypeAndVersion')] + $OverwriteBehavior = 'Never', + + [Switch] + $SkipPackageValidation, + + [String] + $SecurityToken +) + +function Read-XmlElementAsHashtable +{ + Param ( + [System.Xml.XmlElement] + $Element + ) + + $hashtable = @{} + if ($Element.Attributes) + { + $Element.Attributes | + ForEach-Object { + $boolVal = $null + if ([bool]::TryParse($_.Value, [ref]$boolVal)) { + $hashtable[$_.Name] = $boolVal + } + else { + $hashtable[$_.Name] = $_.Value + } + } + } + + return $hashtable +} + +function Read-PublishProfile +{ + Param ( + [ValidateScript({Test-Path $_ -PathType Leaf})] + [String] + $PublishProfileFile + ) + + $publishProfileXml = [Xml] (Get-Content $PublishProfileFile) + $publishProfile = @{} + + $publishProfile.ClusterConnectionParameters = Read-XmlElementAsHashtable $publishProfileXml.PublishProfile.Item("ClusterConnectionParameters") + $publishProfile.UpgradeDeployment = Read-XmlElementAsHashtable $publishProfileXml.PublishProfile.Item("UpgradeDeployment") + + if ($publishProfileXml.PublishProfile.Item("UpgradeDeployment")) + { + $publishProfile.UpgradeDeployment.Parameters = Read-XmlElementAsHashtable $publishProfileXml.PublishProfile.Item("UpgradeDeployment").Item("Parameters") + if ($publishProfile.UpgradeDeployment["Mode"]) + { + $publishProfile.UpgradeDeployment.Parameters[$publishProfile.UpgradeDeployment["Mode"]] = $true + } + } + + $publishProfileFolder = (Split-Path $PublishProfileFile) + $publishProfile.ApplicationParameterFile = [System.IO.Path]::Combine($PublishProfileFolder, $publishProfileXml.PublishProfile.ApplicationParameterFile.Path) + + return $publishProfile +} + +$LocalFolder = (Split-Path $MyInvocation.MyCommand.Path) + +if (!$PublishProfileFile) +{ + $PublishProfileFile = "$LocalFolder\..\PublishProfiles\Local.xml" +} + +if (!$ApplicationPackagePath) +{ + $ApplicationPackagePath = "$LocalFolder\..\pkg\Release" +} + +$ApplicationPackagePath = Resolve-Path $ApplicationPackagePath + +$publishProfile = Read-PublishProfile $PublishProfileFile + +if (-not $UseExistingClusterConnection) +{ + $ClusterConnectionParameters = $publishProfile.ClusterConnectionParameters + if ($SecurityToken) + { + $ClusterConnectionParameters["SecurityToken"] = $SecurityToken + } + + try + { + [void](Connect-ServiceFabricCluster @ClusterConnectionParameters) + } + catch [System.Fabric.FabricObjectClosedException] + { + Write-Warning "Service Fabric cluster may not be connected." + throw + } +} + +$RegKey = "HKLM:\SOFTWARE\Microsoft\Service Fabric SDK" +$ModuleFolderPath = (Get-ItemProperty -Path $RegKey -Name FabricSDKPSModulePath).FabricSDKPSModulePath +Import-Module "$ModuleFolderPath\ServiceFabricSDK.psm1" + +$IsUpgrade = ($publishProfile.UpgradeDeployment -and $publishProfile.UpgradeDeployment.Enabled -and $OverrideUpgradeBehavior -ne 'VetoUpgrade') -or $OverrideUpgradeBehavior -eq 'ForceUpgrade' + +if ($IsUpgrade) +{ + $Action = "RegisterAndUpgrade" + if ($DeployOnly) + { + $Action = "Register" + } + + $UpgradeParameters = $publishProfile.UpgradeDeployment.Parameters + + if ($OverrideUpgradeBehavior -eq 'ForceUpgrade') + { + # Warning: Do not alter these upgrade parameters. It will create an inconsistency with Visual Studio's behavior. + $UpgradeParameters = @{ UnmonitoredAuto = $true; Force = $true } + } + + Publish-UpgradedServiceFabricApplication -ApplicationPackagePath $ApplicationPackagePath -ApplicationParameterFilePath $publishProfile.ApplicationParameterFile -Action $Action -UpgradeParameters $UpgradeParameters -ApplicationParameter $ApplicationParameter -UnregisterUnusedVersions:$UnregisterUnusedApplicationVersionsAfterUpgrade -ErrorAction Stop +} +else +{ + $Action = "RegisterAndCreate" + if ($DeployOnly) + { + $Action = "Register" + } + + Publish-NewServiceFabricApplication -ApplicationPackagePath $ApplicationPackagePath -ApplicationParameterFilePath $publishProfile.ApplicationParameterFile -Action $Action -ApplicationParameter $ApplicationParameter -OverwriteBehavior $OverwriteBehavior -SkipPackageValidation:$SkipPackageValidation -ErrorAction Stop +} \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/TestFabricApplication.sfproj b/Test/TestFabricApplication/TestFabricApplication/TestFabricApplication.sfproj new file mode 100644 index 000000000..ddb330094 --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/TestFabricApplication.sfproj @@ -0,0 +1,38 @@ + + + + + ca924781-ae52-45fa-a817-c39c822fb782 + 1.1 + + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + + + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Service Fabric Tools\Microsoft.VisualStudio.Azure.Fabric.ApplicationProject.targets + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/packages.config b/Test/TestFabricApplication/TestFabricApplication/packages.config new file mode 100644 index 000000000..debf3eb2f --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/ApplicationManifest.xml b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/ApplicationManifest.xml new file mode 100644 index 000000000..288a24134 --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/ApplicationManifest.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Code/TestStatefulService.exe.config b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Code/TestStatefulService.exe.config new file mode 100644 index 000000000..6584bb47e --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Code/TestStatefulService.exe.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Code/TestStatefulService.pdb b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Code/TestStatefulService.pdb new file mode 100644 index 0000000000000000000000000000000000000000..76cc3b4bc8c81420871924765cc655bc2e45a521 GIT binary patch literal 24064 zcmeHP4RBP|6}~SC3n2su0wRJe0ZRnjBoH7l2qb|(gdmb=Q6jL}yug;Qi@O_2{9OdA zojL+)XVhW~Q){ucty5{oT6D0r6dj%V({^ywsee@44sR_a3#uKqMRuH^;nH#Z{9gd28#cy)%3zCHehF&aV@IEcs6qBY2c? zz$8U7zdb+$2aac;H*27rbNFa))d){-UmYf5FF%O7<;o|u59MI#(vt>N<({nYD zZv4;9jDOD^@RXk2<14jp_5Jpn7Si9InYZt?*Cs67^Tw~=d#ci2X^JwB=!VxXpPHKF z&d!9-5)GtV|J)JX_MdTfCzYNhUCcDI0}W)xzXRp;f~+qZFQ0p`?<)m6>coM|ew?-E znFWjQd+(nw7wnj;;&~5z=jwvyR|=k-D8v{2YM%UH_=w}Hem1!Fw$H;gfvsh0hH4!h znc7&s{mTv3uK0>K=MLNc#i7BA2lN85I+p23 zhZ^|$qpv^WL2ec9`9<}thJ}k7mPPzcw!Lw&zp1s+A8HCVG_^+jjV*S}A6?&2Z%1SD zr`q2b2?i=QZfpq#{IOs-Bvb2R{+Qj|+EQmnHU$HAgQg2M*`ZinxHS^6eSxSD&9fTT zu4~w+1g%diC`Lj2X_kWgE1FqK=^M@6fVHcx}YLfxYPdPHapt@BWr^ zibpyd6FoX;+8K-fL1=t$FzE)BBW?U}90<^43r+xPkL33$uKR$jNzj?)wKHyXx;X`!CGR`u)%Mt)ZM+ zF&}wCqhFR84pkls%O>;2yh< z#&~$T@r2ASkMn$g%eQ}EGw(l`hy{a&6xK?BFmb5_n5oK z%C)Xh*Rc&gXH9}fm&Z`AT=!aK`^vzR>k;coyaZ(XhYN23_bZ^ZcL>TogZd;cKiT?5 zMe56}?>-3Upeo}4Yb#!u$?2=&*hsg$1)*lFcATMws#l&$?v1g7`$l2cUdEP^_tJ%wI9eDvZB?DSZnXQMh$n z;kNq1ZFgmDna=v{$@hz>XcHk3z^-hIm{=#mqDj;sr5Pc)_C0)##kG44kp1KOnGM+t zuLPZk{xZB8^iduD3+Ody8`IlB&AMKP@=8CJqqkAu*MM}whaY_%=ShaN7_m zh;w~2{b@}Pf}%|P&!8w1r(ULjzNhow*OYpiiu8QYGSG>j~1G##($B+z-tU##N~fmR^?Q&1o1uXH+^BSG02S|tU_wp5A{ zqS_?E&J2MqzCy-_iB$+U=`d#n?H*={3kt+i86&TJah?o+ieK6#_dd2C@xRL4%uiP| z!1ZYMf6iq>p(64Z>%?;eA(^Gze`o*qB9UcHzI*@gNq&Fj$!s0g6ZJS4h@hOK#t+D{ zMEo7-iT1+i`FX8p`f>(v#PZ}KU1s@s%Hp_m;=F+hw6Po~$}qNk7aIbAzu*AukY|XI zQENw|{lVU~LXdrS{HW$&$lv1P$+i$@ovaVw zO+U@_0k&U;vj$tW?*0sh%^|=qasal#Q=;1>T(Y|$GmG-+$Wf*_55KEr-t0&e@RfvT zp^>S5Pa~T88j3m(0$InDWBL-L?FL4XzFgNolX^6LTE>YAn5&5V?Te;H_`IGz7;}gdLhG--ZKJ*1UK_-PLBwwA+PuG1%bd@R9YEjO0LIo+m?Co# z?ip%A!C27W61+~{UswBsEtK9h`KHg0r;(oz`4^|iUv6L9sxD+Bv98KA=k_A38G^gd z10l1#J(=N+U9v5vkGs;y8w7b(>E$_!?aEyG1pQhBRC|o&>`k0nvw;N2j$;nfM#ZTE z-l2>I9S)i+u9WASe4LQzr;s1(DO+oCJxjpSly@|Yz}t{M8!7z_(jsWA7$r(!VabDM zXJscX$Hua33y@HXI-KKEG!Ob&Y#aSH+8X+8LqVs3(qDw%7Uw#d0jm6|Ld1kVr_G0< zogl-e50s;9pXJy@*mto8NI)N@eENNCmyu7ukMgnp<2)PB1BITXe|MtXX-P8KXJykY zY2Of)d!6a?0`Ov=t3ll|7a~rXi$K}u8X<1K5p+4?H-XlHo+z7r9+xDaD0^Z#YtGH%HqGO9 zP|nNmIy@F9@lZA)J&&E5$6cDo-42fhNj%gVPtW6C&Er1J<9>(7{3IS~-KOX9Bh6#C z=CQ}&F;DXN6#e5^Q||=caeM&eo<0i5Il2hA2Dllx1GpD>2>2!t8?G1uoDHl8ZUfSH zIRHEiJO<>RT22LLpxZS-J8Jw=jthZv)&P>EwU=4iFO_~F3T#B8Da-s*@&7Y-zMX%L zz&(n7X|?uoO0Xsfw5bM=mRHI|ra*4klv}%Ff2l(25(I3g<3o4sHup;}5$j z0PV3xfLigVM#o>UwmfFtk~bQcMCQzuZHcWx-PTV~j{63|!k?M1G$*`=A)Eu7MjM8` zDNbFJ4iclJeanNE4G*PX%h9`=2hL4#_IV5_%XuX)-oH*svXkcSg6&@h22H>lfO~-l zfQNx+61e`&*u3m~&*^8o;#{gfm<`*|Ha=zExQZad(VacN0F8UaytH@cM=_2AsNDZ^;9cm*+~SY9Pw&8b zei-fMSYLuLX&aEVLep1u`i;8WtD4@b(;v_j{)?=4xz0Ct2eyt|x?CxklmASeewD80 z*Xcje@uzk9zv=i}I-hr*tlvk|uXMR#n%}=oeI4Ja%jIKiSnp$<{;W>FLf3y%*K5=1 zHJYBM^T+CZ3w*L@JQSD_M`;DjKN*mh1K{t5lhsejcjOu#CnT5*O=bI2(p1zd3G-D* zrT$O9X>&;Bm`&T>lPIbOy%J(b{crpLdm}OyM9vk0)maZSl(Yz3Q5hNS= z9@ueXZZ&rjuAQhm89QRCTyvRi>Z&rjZgXPK;F_{h_6(J# z%a-Du2d$?^u&6B2@uA(wQ)M*|?3ZRADU<6nao{%PRk|)emG2WJ_DqjRKG2yuY^TTU zo7j6Y(6cpwspA0cJD+RdK0`ukUJ3HdGuYHTJ{!2XoqD{t$1{htJb52)?&4E<@}Av1 z*GkRf{ds$NyccgTkN4f}DASKMm}CXKYO^T83eQJ4m>CCC{(iL=DobZpii@A{ zeQern?jKECNSViUo*`3#dAv`pOwB-?c`Jb1b)J#ID8om9g^U2q{9~ATx%lB-C&&BS zxutaXcn^B#P_ca#p9}I`Fg}-=j4;nS2H2MKWaPsGCaq(A7Kk^s@Ox3g#Y$FBH&4=} ziD^@3&MdDktL&W2fzBB6jNKWTdcI(;lvYovD8ufopyR#`7Q6L=eiZuZjGPnaikMb8 zea4Kk8C6nX$MW*U<61~(*FhRx`Zzhu7nDwg+_LWctgjwObpB ze-G^68t`}#bRP5IAR#C&0W?>Yup2pkLa0>=Tz12d4Ufr-h{Oe~{; Tj0Q3q$Y>y=fs6)vfd>8y_4tz$ literal 0 HcmV?d00001 diff --git a/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Config/Settings.xml b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Config/Settings.xml new file mode 100644 index 000000000..be6a4cdfa --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Config/Settings.xml @@ -0,0 +1,16 @@ + + + +
+ +
+ +
+ + + + diff --git a/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/ServiceManifest.xml b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/ServiceManifest.xml new file mode 100644 index 000000000..945186899 --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/ServiceManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + TestStatefulService.exe + + + + + + + + + + + + + + + + + diff --git a/Test/TestFabricApplication/TestStatefulService/App.config b/Test/TestFabricApplication/TestStatefulService/App.config new file mode 100644 index 000000000..6584bb47e --- /dev/null +++ b/Test/TestFabricApplication/TestStatefulService/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestStatefulService/PackageRoot/Config/Settings.xml b/Test/TestFabricApplication/TestStatefulService/PackageRoot/Config/Settings.xml new file mode 100644 index 000000000..be6a4cdfa --- /dev/null +++ b/Test/TestFabricApplication/TestStatefulService/PackageRoot/Config/Settings.xml @@ -0,0 +1,16 @@ + + + +
+ +
+ +
+ + + + diff --git a/Test/TestFabricApplication/TestStatefulService/PackageRoot/ServiceManifest.xml b/Test/TestFabricApplication/TestStatefulService/PackageRoot/ServiceManifest.xml new file mode 100644 index 000000000..945186899 --- /dev/null +++ b/Test/TestFabricApplication/TestStatefulService/PackageRoot/ServiceManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + TestStatefulService.exe + + + + + + + + + + + + + + + + + diff --git a/Test/TestFabricApplication/TestStatefulService/Program.cs b/Test/TestFabricApplication/TestStatefulService/Program.cs new file mode 100644 index 000000000..d6b3d133c --- /dev/null +++ b/Test/TestFabricApplication/TestStatefulService/Program.cs @@ -0,0 +1,38 @@ +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.ServiceFabric.Services.Runtime; + +namespace TestStatefulService +{ + internal static class Program + { + /// + /// This is the entry point of the service host process. + /// + private static void Main() + { + try + { + // The ServiceManifest.XML file defines one or more service type names. + // Registering a service maps a service type name to a .NET type. + // When Service Fabric creates an instance of this service type, + // an instance of the class is created in this host process. + + ServiceRuntime.RegisterServiceAsync("TestStatefulServiceType", + context => new TestStatefulService(context)).GetAwaiter().GetResult(); + + ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(TestStatefulService).Name); + + // Prevents this host process from terminating so services keep running. + Thread.Sleep(Timeout.Infinite); + } + catch (Exception e) + { + ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString()); + throw; + } + } + } +} diff --git a/Test/TestFabricApplication/TestStatefulService/Properties/AssemblyInfo.cs b/Test/TestFabricApplication/TestStatefulService/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..20f4597a8 --- /dev/null +++ b/Test/TestFabricApplication/TestStatefulService/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TestStatefulService")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TestStatefulService")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("95d6c9c7-f7a0-4125-840d-1854bec24978")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Test/TestFabricApplication/TestStatefulService/ServiceEventSource.cs b/Test/TestFabricApplication/TestStatefulService/ServiceEventSource.cs new file mode 100644 index 000000000..459178341 --- /dev/null +++ b/Test/TestFabricApplication/TestStatefulService/ServiceEventSource.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.Tracing; +using System.Fabric; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.ServiceFabric.Services.Runtime; + +namespace TestStatefulService +{ + [EventSource(Name = "MyCompany-TestFabricApplication-TestStatefulService")] + internal sealed class ServiceEventSource : EventSource + { + public static readonly ServiceEventSource Current = new ServiceEventSource(); + + static ServiceEventSource() + { + // A workaround for the problem where ETW activities do not get tracked until Tasks infrastructure is initialized. + // This problem will be fixed in .NET Framework 4.6.2. + Task.Run(() => { }); + } + + // Instance constructor is private to enforce singleton semantics + private ServiceEventSource() : base() { } + + #region Keywords + // Event keywords can be used to categorize events. + // Each keyword is a bit flag. A single event can be associated with multiple keywords (via EventAttribute.Keywords property). + // Keywords must be defined as a public class named 'Keywords' inside EventSource that uses them. + public static class Keywords + { + public const EventKeywords Requests = (EventKeywords)0x1L; + public const EventKeywords ServiceInitialization = (EventKeywords)0x2L; + } + #endregion + + #region Events + // Define an instance method for each event you want to record and apply an [Event] attribute to it. + // The method name is the name of the event. + // Pass any parameters you want to record with the event (only primitive integer types, DateTime, Guid & string are allowed). + // Each event method implementation should check whether the event source is enabled, and if it is, call WriteEvent() method to raise the event. + // The number and types of arguments passed to every event method must exactly match what is passed to WriteEvent(). + // Put [NonEvent] attribute on all methods that do not define an event. + // For more information see https://msdn.microsoft.com/en-us/library/system.diagnostics.tracing.eventsource.aspx + + [NonEvent] + public void Message(string message, params object[] args) + { + if (this.IsEnabled()) + { + string finalMessage = string.Format(message, args); + Message(finalMessage); + } + } + + private const int MessageEventId = 1; + [Event(MessageEventId, Level = EventLevel.Informational, Message = "{0}")] + public void Message(string message) + { + if (this.IsEnabled()) + { + WriteEvent(MessageEventId, message); + } + } + + [NonEvent] + public void ServiceMessage(StatefulService service, string message, params object[] args) + { + if (this.IsEnabled()) + { + string finalMessage = string.Format(message, args); + ServiceMessage( + service.Context.ServiceName.ToString(), + service.Context.ServiceTypeName, + service.Context.ReplicaId, + service.Context.PartitionId, + service.Context.CodePackageActivationContext.ApplicationName, + service.Context.CodePackageActivationContext.ApplicationTypeName, + service.Context.NodeContext.NodeName, + finalMessage); + } + } + + // For very high-frequency events it might be advantageous to raise events using WriteEventCore API. + // This results in more efficient parameter handling, but requires explicit allocation of EventData structure and unsafe code. + // To enable this code path, define UNSAFE conditional compilation symbol and turn on unsafe code support in project properties. + private const int ServiceMessageEventId = 2; + [Event(ServiceMessageEventId, Level = EventLevel.Informational, Message = "{7}")] + private +#if UNSAFE + unsafe +#endif + void ServiceMessage( + string serviceName, + string serviceTypeName, + long replicaOrInstanceId, + Guid partitionId, + string applicationName, + string applicationTypeName, + string nodeName, + string message) + { +#if !UNSAFE + WriteEvent(ServiceMessageEventId, serviceName, serviceTypeName, replicaOrInstanceId, partitionId, applicationName, applicationTypeName, nodeName, message); +#else + const int numArgs = 8; + fixed (char* pServiceName = serviceName, pServiceTypeName = serviceTypeName, pApplicationName = applicationName, pApplicationTypeName = applicationTypeName, pNodeName = nodeName, pMessage = message) + { + EventData* eventData = stackalloc EventData[numArgs]; + eventData[0] = new EventData { DataPointer = (IntPtr) pServiceName, Size = SizeInBytes(serviceName) }; + eventData[1] = new EventData { DataPointer = (IntPtr) pServiceTypeName, Size = SizeInBytes(serviceTypeName) }; + eventData[2] = new EventData { DataPointer = (IntPtr) (&replicaOrInstanceId), Size = sizeof(long) }; + eventData[3] = new EventData { DataPointer = (IntPtr) (&partitionId), Size = sizeof(Guid) }; + eventData[4] = new EventData { DataPointer = (IntPtr) pApplicationName, Size = SizeInBytes(applicationName) }; + eventData[5] = new EventData { DataPointer = (IntPtr) pApplicationTypeName, Size = SizeInBytes(applicationTypeName) }; + eventData[6] = new EventData { DataPointer = (IntPtr) pNodeName, Size = SizeInBytes(nodeName) }; + eventData[7] = new EventData { DataPointer = (IntPtr) pMessage, Size = SizeInBytes(message) }; + + WriteEventCore(ServiceMessageEventId, numArgs, eventData); + } +#endif + } + + private const int ServiceTypeRegisteredEventId = 3; + [Event(ServiceTypeRegisteredEventId, Level = EventLevel.Informational, Message = "Service host process {0} registered service type {1}", Keywords = Keywords.ServiceInitialization)] + public void ServiceTypeRegistered(int hostProcessId, string serviceType) + { + WriteEvent(ServiceTypeRegisteredEventId, hostProcessId, serviceType); + } + + private const int ServiceHostInitializationFailedEventId = 4; + [Event(ServiceHostInitializationFailedEventId, Level = EventLevel.Error, Message = "Service host initialization failed", Keywords = Keywords.ServiceInitialization)] + public void ServiceHostInitializationFailed(string exception) + { + WriteEvent(ServiceHostInitializationFailedEventId, exception); + } + + // A pair of events sharing the same name prefix with a "Start"/"Stop" suffix implicitly marks boundaries of an event tracing activity. + // These activities can be automatically picked up by debugging and profiling tools, which can compute their execution time, child activities, + // and other statistics. + private const int ServiceRequestStartEventId = 5; + [Event(ServiceRequestStartEventId, Level = EventLevel.Informational, Message = "Service request '{0}' started", Keywords = Keywords.Requests)] + public void ServiceRequestStart(string requestTypeName) + { + WriteEvent(ServiceRequestStartEventId, requestTypeName); + } + + private const int ServiceRequestStopEventId = 6; + [Event(ServiceRequestStopEventId, Level = EventLevel.Informational, Message = "Service request '{0}' finished", Keywords = Keywords.Requests)] + public void ServiceRequestStop(string requestTypeName) + { + WriteEvent(ServiceRequestStopEventId, requestTypeName); + } + + private const int ServiceRequestFailedEventId = 7; + [Event(ServiceRequestFailedEventId, Level = EventLevel.Error, Message = "Service request '{0}' failed", Keywords = Keywords.Requests)] + public void ServiceRequestFailed(string requestTypeName, string exception) + { + WriteEvent(ServiceRequestFailedEventId, exception); + } + #endregion + + #region Private methods +#if UNSAFE + private int SizeInBytes(string s) + { + if (s == null) + { + return 0; + } + else + { + return (s.Length + 1) * sizeof(char); + } + } +#endif + #endregion + } +} diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs new file mode 100644 index 000000000..6e547c2f7 --- /dev/null +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Fabric; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.ServiceFabric.Data.Collections; +using Microsoft.ServiceFabric.Services.Communication.Runtime; +using Microsoft.ServiceFabric.Services.Runtime; + +namespace TestStatefulService +{ + /// + /// An instance of this class is created for each service replica by the Service Fabric runtime. + /// + internal sealed class TestStatefulService : StatefulService + { + public TestStatefulService(StatefulServiceContext context) + : base(context) + { } + + /// + /// Optional override to create listeners (e.g., HTTP, Service Remoting, WCF, etc.) for this service replica to handle client or user requests. + /// + /// + /// For more information on service communication, see http://aka.ms/servicefabricservicecommunication + /// + /// A collection of listeners. + protected override IEnumerable CreateServiceReplicaListeners() + { + return new ServiceReplicaListener[0]; + } + + /// + /// This is the main entry point for your service replica. + /// This method executes when this replica of your service becomes primary and has write status. + /// + /// Canceled when Service Fabric needs to shut down this service replica. + protected override async Task RunAsync(CancellationToken cancellationToken) + { + // TODO: Replace the following sample code with your own logic + // or remove this RunAsync override if it's not needed in your service. + + var myDictionary = await this.StateManager.GetOrAddAsync>("myDictionary"); + + while (true) + { + cancellationToken.ThrowIfCancellationRequested(); + + using (var tx = this.StateManager.CreateTransaction()) + { + var result = await myDictionary.TryGetValueAsync(tx, "Counter"); + + ServiceEventSource.Current.ServiceMessage(this, "Current Counter Value: {0}", + result.HasValue ? result.Value.ToString() : "Value does not exist."); + + await myDictionary.AddOrUpdateAsync(tx, "Counter", 0, (key, value) => ++value); + + // If an exception is thrown before calling CommitAsync, the transaction aborts, all changes are + // discarded, and nothing is saved to the secondary replicas. + await tx.CommitAsync(); + } + + await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken); + } + } + } +} diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj new file mode 100644 index 000000000..1d148f7c7 --- /dev/null +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj @@ -0,0 +1,93 @@ + + + + + Debug + x64 + {95D6C9C7-F7A0-4125-840D-1854BEC24978} + Exe + Properties + TestStatefulService + TestStatefulService + v4.5.2 + 512 + true + + + true + full + false + bin\x64\Debug\ + DEBUG;TRACE + prompt + x64 + MinimumRecommendedRules.ruleset + + + pdbonly + true + bin\x64\Release\ + TRACE + prompt + x64 + MinimumRecommendedRules.ruleset + + + $(AdditionalFileItemNames);None + + + + ..\..\..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll + True + + + ..\..\..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll + True + + + ..\..\..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.dll + True + + + ..\..\..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll + True + + + ..\..\..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\Microsoft.ServiceFabric.Services.dll + True + + + ..\..\..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\ServiceFabricServiceModel.dll + True + + + + + ..\..\..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\System.Fabric.dll + True + + + + + + + + + + + + + + + Designer + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestStatefulService/packages.config b/Test/TestFabricApplication/TestStatefulService/packages.config new file mode 100644 index 000000000..585a287bd --- /dev/null +++ b/Test/TestFabricApplication/TestStatefulService/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From a04256257d35d959a304529bf25fc45528a120e4 Mon Sep 17 00:00:00 2001 From: pradeek Date: Thu, 18 Aug 2016 15:37:07 -0700 Subject: [PATCH 009/210] Code to be able to do F5 and test an orchestration by hitting break points. Eventually I will write a controller to expose the functionality and stateless app to test it and use that for unit testing. --- DurableTask.ServiceFabric.sln | 11 ++ .../TestApplication.Common/IOwinAppBuilder.cs | 9 ++ .../OwinCommunicationListener.cs | 126 ++++++++++++++++++ .../Properties/AssemblyInfo.cs | 36 +++++ .../TestApplication.Common.csproj | 99 ++++++++++++++ .../TestApplication.Common/packages.config | 9 ++ .../TestStatefulService/App.config | 14 +- .../DebugHelper/TestExecutor.cs | 38 ++++++ .../PackageRoot/ServiceManifest.xml | 2 +- .../TestStatefulService/Startup.cs | 26 ++++ .../TestOrchestrations/GetUserTask.cs | 12 ++ .../TestOrchestrations/GreetUserTask.cs | 12 ++ .../SimpleOrchestrationWithTasks.cs | 17 +++ .../TestStatefulService.cs | 58 ++++---- .../TestStatefulService.csproj | 57 ++++++++ .../TestStatefulService/packages.config | 9 ++ 16 files changed, 510 insertions(+), 25 deletions(-) create mode 100644 Test/TestFabricApplication/TestApplication.Common/IOwinAppBuilder.cs create mode 100644 Test/TestFabricApplication/TestApplication.Common/OwinCommunicationListener.cs create mode 100644 Test/TestFabricApplication/TestApplication.Common/Properties/AssemblyInfo.cs create mode 100644 Test/TestFabricApplication/TestApplication.Common/TestApplication.Common.csproj create mode 100644 Test/TestFabricApplication/TestApplication.Common/packages.config create mode 100644 Test/TestFabricApplication/TestStatefulService/DebugHelper/TestExecutor.cs create mode 100644 Test/TestFabricApplication/TestStatefulService/Startup.cs create mode 100644 Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GetUserTask.cs create mode 100644 Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GreetUserTask.cs create mode 100644 Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTasks.cs diff --git a/DurableTask.ServiceFabric.sln b/DurableTask.ServiceFabric.sln index 662929471..0d29c59fb 100644 --- a/DurableTask.ServiceFabric.sln +++ b/DurableTask.ServiceFabric.sln @@ -28,6 +28,8 @@ Project("{A07B5EB6-E848-4116-A8D0-A826331D98C6}") = "TestFabricApplication", "Te EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestStatefulService", "Test\TestFabricApplication\TestStatefulService\TestStatefulService.csproj", "{95D6C9C7-F7A0-4125-840D-1854BEC24978}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.Common", "Test\TestFabricApplication\TestApplication.Common\TestApplication.Common.csproj", "{EA90334D-3194-4266-81EB-EECA9C760315}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -82,6 +84,14 @@ Global {95D6C9C7-F7A0-4125-840D-1854BEC24978}.Release|Any CPU.ActiveCfg = Release|x64 {95D6C9C7-F7A0-4125-840D-1854BEC24978}.Release|x64.ActiveCfg = Release|x64 {95D6C9C7-F7A0-4125-840D-1854BEC24978}.Release|x64.Build.0 = Release|x64 + {EA90334D-3194-4266-81EB-EECA9C760315}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA90334D-3194-4266-81EB-EECA9C760315}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA90334D-3194-4266-81EB-EECA9C760315}.Debug|x64.ActiveCfg = Debug|Any CPU + {EA90334D-3194-4266-81EB-EECA9C760315}.Debug|x64.Build.0 = Debug|Any CPU + {EA90334D-3194-4266-81EB-EECA9C760315}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA90334D-3194-4266-81EB-EECA9C760315}.Release|Any CPU.Build.0 = Release|Any CPU + {EA90334D-3194-4266-81EB-EECA9C760315}.Release|x64.ActiveCfg = Release|Any CPU + {EA90334D-3194-4266-81EB-EECA9C760315}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -94,6 +104,7 @@ Global {507C0CC2-082F-4EB7-8984-E2648976EB04} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} {CA924781-AE52-45FA-A817-C39C822FB782} = {507C0CC2-082F-4EB7-8984-E2648976EB04} {95D6C9C7-F7A0-4125-840D-1854BEC24978} = {507C0CC2-082F-4EB7-8984-E2648976EB04} + {EA90334D-3194-4266-81EB-EECA9C760315} = {507C0CC2-082F-4EB7-8984-E2648976EB04} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EnterpriseLibraryConfigurationToolBinariesPath = packages\TransientFaultHandling.Core.5.1.1209.1\lib\NET4 diff --git a/Test/TestFabricApplication/TestApplication.Common/IOwinAppBuilder.cs b/Test/TestFabricApplication/TestApplication.Common/IOwinAppBuilder.cs new file mode 100644 index 000000000..0e00f414c --- /dev/null +++ b/Test/TestFabricApplication/TestApplication.Common/IOwinAppBuilder.cs @@ -0,0 +1,9 @@ +using Owin; + +namespace TestApplication.Common +{ + public interface IOwinAppBuilder + { + void Configuration(IAppBuilder appBuilder); + } +} diff --git a/Test/TestFabricApplication/TestApplication.Common/OwinCommunicationListener.cs b/Test/TestFabricApplication/TestApplication.Common/OwinCommunicationListener.cs new file mode 100644 index 000000000..bdc1a5575 --- /dev/null +++ b/Test/TestFabricApplication/TestApplication.Common/OwinCommunicationListener.cs @@ -0,0 +1,126 @@ +using System; +using System.Diagnostics; +using System.Fabric; +using System.Fabric.Description; +using System.Globalization; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Owin.Hosting; +using Microsoft.ServiceFabric.Services.Communication.Runtime; + +namespace TestApplication.Common +{ + public class OwinCommunicationListener : ICommunicationListener + { + private readonly ServiceContext serviceContext; + + /// + /// OWIN server handle. + /// + private IDisposable serverHandle; + + private IOwinAppBuilder startup; + private string publishAddress; + private string listeningAddress; + private string appRoot; + + public OwinCommunicationListener(IOwinAppBuilder startup, ServiceContext serviceContext) + : this(null, startup, serviceContext) + { + } + + public OwinCommunicationListener(string appRoot, IOwinAppBuilder startup, ServiceContext serviceContext) + { + this.startup = startup; + this.appRoot = appRoot; + this.serviceContext = serviceContext; + } + + public Task OpenAsync(CancellationToken cancellationToken) + { + Trace.WriteLine("Initialize"); + + EndpointResourceDescription serviceEndpoint = this.serviceContext.CodePackageActivationContext.GetEndpoint("ServiceEndpoint"); + int port = serviceEndpoint.Port; + + if (this.serviceContext is StatefulServiceContext) + { + StatefulServiceContext statefulInitParams = (StatefulServiceContext)this.serviceContext; + + this.listeningAddress = String.Format( + CultureInfo.InvariantCulture, + "http://+:{0}/{1}/{2}/{3}/", + port, + statefulInitParams.PartitionId, + statefulInitParams.ReplicaId, + Guid.NewGuid()); + } + else if (this.serviceContext is StatelessServiceContext) + { + this.listeningAddress = String.Format( + CultureInfo.InvariantCulture, + "http://+:{0}/{1}", + port, + string.IsNullOrWhiteSpace(this.appRoot) + ? "" + : this.appRoot.TrimEnd('/') + '/'); + } + else + { + throw new InvalidOperationException(); + } + + this.publishAddress = this.listeningAddress.Replace("+", FabricRuntime.GetNodeContext().IPAddressOrFQDN); + + Trace.WriteLine(String.Format("Opening on {0}", this.publishAddress)); + + try + { + Trace.WriteLine(String.Format("Starting web server on {0}", this.listeningAddress)); + + this.serverHandle = WebApp.Start(this.listeningAddress, appBuilder => this.startup.Configuration(appBuilder)); + + return Task.FromResult(this.publishAddress); + } + catch (Exception ex) + { + Trace.WriteLine(ex); + + this.StopWebServer(); + + throw; + } + } + + public Task CloseAsync(CancellationToken cancellationToken) + { + Trace.WriteLine("Close"); + + this.StopWebServer(); + + return Task.FromResult(true); + } + + public void Abort() + { + Trace.WriteLine("Abort"); + + this.StopWebServer(); + } + + private void StopWebServer() + { + if (this.serverHandle != null) + { + try + { + this.serverHandle.Dispose(); + } + catch (ObjectDisposedException) + { + // no-op + } + } + } + } +} diff --git a/Test/TestFabricApplication/TestApplication.Common/Properties/AssemblyInfo.cs b/Test/TestFabricApplication/TestApplication.Common/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..0e092139d --- /dev/null +++ b/Test/TestFabricApplication/TestApplication.Common/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("TestApplication.Common")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TestApplication.Common")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ea90334d-3194-4266-81eb-eeca9c760315")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Test/TestFabricApplication/TestApplication.Common/TestApplication.Common.csproj b/Test/TestFabricApplication/TestApplication.Common/TestApplication.Common.csproj new file mode 100644 index 000000000..a34f676ab --- /dev/null +++ b/Test/TestFabricApplication/TestApplication.Common/TestApplication.Common.csproj @@ -0,0 +1,99 @@ + + + + + Debug + AnyCPU + {EA90334D-3194-4266-81EB-EECA9C760315} + Library + Properties + TestApplication.Common + TestApplication.Common + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll + True + + + ..\..\..\packages\Microsoft.Owin.Hosting.3.0.1\lib\net45\Microsoft.Owin.Hosting.dll + True + + + ..\..\..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll + True + + + ..\..\..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll + True + + + ..\..\..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.dll + True + + + ..\..\..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll + True + + + ..\..\..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\Microsoft.ServiceFabric.Services.dll + True + + + ..\..\..\packages\Owin.1.0\lib\net40\Owin.dll + True + + + ..\..\..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\ServiceFabricServiceModel.dll + True + + + + + ..\..\..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\System.Fabric.dll + True + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestApplication.Common/packages.config b/Test/TestFabricApplication/TestApplication.Common/packages.config new file mode 100644 index 000000000..ddee833a8 --- /dev/null +++ b/Test/TestFabricApplication/TestApplication.Common/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestStatefulService/App.config b/Test/TestFabricApplication/TestStatefulService/App.config index 6584bb47e..e3d46ecfd 100644 --- a/Test/TestFabricApplication/TestStatefulService/App.config +++ b/Test/TestFabricApplication/TestStatefulService/App.config @@ -1,6 +1,18 @@ - + + + + + + + + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestStatefulService/DebugHelper/TestExecutor.cs b/Test/TestFabricApplication/TestStatefulService/DebugHelper/TestExecutor.cs new file mode 100644 index 000000000..c0908e0df --- /dev/null +++ b/Test/TestFabricApplication/TestStatefulService/DebugHelper/TestExecutor.cs @@ -0,0 +1,38 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using DurableTask; +using TestStatefulService.TestOrchestrations; + +namespace TestStatefulService.DebugHelper +{ + class TestExecutor + { + TaskHubClient client; + CancellationTokenSource cancellationTokenSource; + + public TestExecutor(TaskHubClient client) + { + this.client = client; + this.cancellationTokenSource = new CancellationTokenSource(); + } + + public Task StartAsync() + { + var startTask = Task.Run(async () => + { + var instance = await client.CreateOrchestrationInstanceAsync(typeof(SimpleOrchestrationWithTasks), input: null); + var state = await client.WaitForOrchestrationAsync(instance, TimeSpan.FromMinutes(10)); + var result = state.Output; + }, this.cancellationTokenSource.Token); + + return Task.FromResult(null); + } + + public Task StopAsync() + { + this.cancellationTokenSource.Cancel(); + return Task.FromResult(null); + } + } +} diff --git a/Test/TestFabricApplication/TestStatefulService/PackageRoot/ServiceManifest.xml b/Test/TestFabricApplication/TestStatefulService/PackageRoot/ServiceManifest.xml index 945186899..3d2fbe543 100644 --- a/Test/TestFabricApplication/TestStatefulService/PackageRoot/ServiceManifest.xml +++ b/Test/TestFabricApplication/TestStatefulService/PackageRoot/ServiceManifest.xml @@ -28,7 +28,7 @@ - + - - - - - - - - - - - - - \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Code/TestStatefulService.exe.config b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Code/TestStatefulService.exe.config deleted file mode 100644 index 6584bb47e..000000000 --- a/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Code/TestStatefulService.exe.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Code/TestStatefulService.pdb b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Code/TestStatefulService.pdb deleted file mode 100644 index 76cc3b4bc8c81420871924765cc655bc2e45a521..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24064 zcmeHP4RBP|6}~SC3n2su0wRJe0ZRnjBoH7l2qb|(gdmb=Q6jL}yug;Qi@O_2{9OdA zojL+)XVhW~Q){ucty5{oT6D0r6dj%V({^ywsee@44sR_a3#uKqMRuH^;nH#Z{9gd28#cy)%3zCHehF&aV@IEcs6qBY2c? zz$8U7zdb+$2aac;H*27rbNFa))d){-UmYf5FF%O7<;o|u59MI#(vt>N<({nYD zZv4;9jDOD^@RXk2<14jp_5Jpn7Si9InYZt?*Cs67^Tw~=d#ci2X^JwB=!VxXpPHKF z&d!9-5)GtV|J)JX_MdTfCzYNhUCcDI0}W)xzXRp;f~+qZFQ0p`?<)m6>coM|ew?-E znFWjQd+(nw7wnj;;&~5z=jwvyR|=k-D8v{2YM%UH_=w}Hem1!Fw$H;gfvsh0hH4!h znc7&s{mTv3uK0>K=MLNc#i7BA2lN85I+p23 zhZ^|$qpv^WL2ec9`9<}thJ}k7mPPzcw!Lw&zp1s+A8HCVG_^+jjV*S}A6?&2Z%1SD zr`q2b2?i=QZfpq#{IOs-Bvb2R{+Qj|+EQmnHU$HAgQg2M*`ZinxHS^6eSxSD&9fTT zu4~w+1g%diC`Lj2X_kWgE1FqK=^M@6fVHcx}YLfxYPdPHapt@BWr^ zibpyd6FoX;+8K-fL1=t$FzE)BBW?U}90<^43r+xPkL33$uKR$jNzj?)wKHyXx;X`!CGR`u)%Mt)ZM+ zF&}wCqhFR84pkls%O>;2yh< z#&~$T@r2ASkMn$g%eQ}EGw(l`hy{a&6xK?BFmb5_n5oK z%C)Xh*Rc&gXH9}fm&Z`AT=!aK`^vzR>k;coyaZ(XhYN23_bZ^ZcL>TogZd;cKiT?5 zMe56}?>-3Upeo}4Yb#!u$?2=&*hsg$1)*lFcATMws#l&$?v1g7`$l2cUdEP^_tJ%wI9eDvZB?DSZnXQMh$n z;kNq1ZFgmDna=v{$@hz>XcHk3z^-hIm{=#mqDj;sr5Pc)_C0)##kG44kp1KOnGM+t zuLPZk{xZB8^iduD3+Ody8`IlB&AMKP@=8CJqqkAu*MM}whaY_%=ShaN7_m zh;w~2{b@}Pf}%|P&!8w1r(ULjzNhow*OYpiiu8QYGSG>j~1G##($B+z-tU##N~fmR^?Q&1o1uXH+^BSG02S|tU_wp5A{ zqS_?E&J2MqzCy-_iB$+U=`d#n?H*={3kt+i86&TJah?o+ieK6#_dd2C@xRL4%uiP| z!1ZYMf6iq>p(64Z>%?;eA(^Gze`o*qB9UcHzI*@gNq&Fj$!s0g6ZJS4h@hOK#t+D{ zMEo7-iT1+i`FX8p`f>(v#PZ}KU1s@s%Hp_m;=F+hw6Po~$}qNk7aIbAzu*AukY|XI zQENw|{lVU~LXdrS{HW$&$lv1P$+i$@ovaVw zO+U@_0k&U;vj$tW?*0sh%^|=qasal#Q=;1>T(Y|$GmG-+$Wf*_55KEr-t0&e@RfvT zp^>S5Pa~T88j3m(0$InDWBL-L?FL4XzFgNolX^6LTE>YAn5&5V?Te;H_`IGz7;}gdLhG--ZKJ*1UK_-PLBwwA+PuG1%bd@R9YEjO0LIo+m?Co# z?ip%A!C27W61+~{UswBsEtK9h`KHg0r;(oz`4^|iUv6L9sxD+Bv98KA=k_A38G^gd z10l1#J(=N+U9v5vkGs;y8w7b(>E$_!?aEyG1pQhBRC|o&>`k0nvw;N2j$;nfM#ZTE z-l2>I9S)i+u9WASe4LQzr;s1(DO+oCJxjpSly@|Yz}t{M8!7z_(jsWA7$r(!VabDM zXJscX$Hua33y@HXI-KKEG!Ob&Y#aSH+8X+8LqVs3(qDw%7Uw#d0jm6|Ld1kVr_G0< zogl-e50s;9pXJy@*mto8NI)N@eENNCmyu7ukMgnp<2)PB1BITXe|MtXX-P8KXJykY zY2Of)d!6a?0`Ov=t3ll|7a~rXi$K}u8X<1K5p+4?H-XlHo+z7r9+xDaD0^Z#YtGH%HqGO9 zP|nNmIy@F9@lZA)J&&E5$6cDo-42fhNj%gVPtW6C&Er1J<9>(7{3IS~-KOX9Bh6#C z=CQ}&F;DXN6#e5^Q||=caeM&eo<0i5Il2hA2Dllx1GpD>2>2!t8?G1uoDHl8ZUfSH zIRHEiJO<>RT22LLpxZS-J8Jw=jthZv)&P>EwU=4iFO_~F3T#B8Da-s*@&7Y-zMX%L zz&(n7X|?uoO0Xsfw5bM=mRHI|ra*4klv}%Ff2l(25(I3g<3o4sHup;}5$j z0PV3xfLigVM#o>UwmfFtk~bQcMCQzuZHcWx-PTV~j{63|!k?M1G$*`=A)Eu7MjM8` zDNbFJ4iclJeanNE4G*PX%h9`=2hL4#_IV5_%XuX)-oH*svXkcSg6&@h22H>lfO~-l zfQNx+61e`&*u3m~&*^8o;#{gfm<`*|Ha=zExQZad(VacN0F8UaytH@cM=_2AsNDZ^;9cm*+~SY9Pw&8b zei-fMSYLuLX&aEVLep1u`i;8WtD4@b(;v_j{)?=4xz0Ct2eyt|x?CxklmASeewD80 z*Xcje@uzk9zv=i}I-hr*tlvk|uXMR#n%}=oeI4Ja%jIKiSnp$<{;W>FLf3y%*K5=1 zHJYBM^T+CZ3w*L@JQSD_M`;DjKN*mh1K{t5lhsejcjOu#CnT5*O=bI2(p1zd3G-D* zrT$O9X>&;Bm`&T>lPIbOy%J(b{crpLdm}OyM9vk0)maZSl(Yz3Q5hNS= z9@ueXZZ&rjuAQhm89QRCTyvRi>Z&rjZgXPK;F_{h_6(J# z%a-Du2d$?^u&6B2@uA(wQ)M*|?3ZRADU<6nao{%PRk|)emG2WJ_DqjRKG2yuY^TTU zo7j6Y(6cpwspA0cJD+RdK0`ukUJ3HdGuYHTJ{!2XoqD{t$1{htJb52)?&4E<@}Av1 z*GkRf{ds$NyccgTkN4f}DASKMm}CXKYO^T83eQJ4m>CCC{(iL=DobZpii@A{ zeQern?jKECNSViUo*`3#dAv`pOwB-?c`Jb1b)J#ID8om9g^U2q{9~ATx%lB-C&&BS zxutaXcn^B#P_ca#p9}I`Fg}-=j4;nS2H2MKWaPsGCaq(A7Kk^s@Ox3g#Y$FBH&4=} ziD^@3&MdDktL&W2fzBB6jNKWTdcI(;lvYovD8ufopyR#`7Q6L=eiZuZjGPnaikMb8 zea4Kk8C6nX$MW*U<61~(*FhRx`Zzhu7nDwg+_LWctgjwObpB ze-G^68t`}#bRP5IAR#C&0W?>Yup2pkLa0>=Tz12d4Ufr-h{Oe~{; Tj0Q3q$Y>y=fs6)vfd>8y_4tz$ diff --git a/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Config/Settings.xml b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Config/Settings.xml deleted file mode 100644 index be6a4cdfa..000000000 --- a/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/Config/Settings.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - -
- -
- -
- - - - diff --git a/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/ServiceManifest.xml b/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/ServiceManifest.xml deleted file mode 100644 index 945186899..000000000 --- a/Test/TestFabricApplication/TestFabricApplication/pkg/Debug/TestStatefulServicePkg/ServiceManifest.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - TestStatefulService.exe - - - - - - - - - - - - - - - - - From 645fbf5bb545837157105eb792ecbcacf6752727 Mon Sep 17 00:00:00 2001 From: pradeek Date: Thu, 18 Aug 2016 16:38:59 -0700 Subject: [PATCH 012/210] Refactoring the activity fetching in fabric orchestration service to a separate class, we can perhaps evolve the implementation as we see fit. --- .../ActivitiesProvider.cs | 81 +++++++++++++++++++ .../DurableTask.ServiceFabric.csproj | 1 + .../FabricOrchestrationService.cs | 44 +++------- DurableTask.ServiceFabric/SessionsProvider.cs | 7 +- 4 files changed, 98 insertions(+), 35 deletions(-) create mode 100644 DurableTask.ServiceFabric/ActivitiesProvider.cs diff --git a/DurableTask.ServiceFabric/ActivitiesProvider.cs b/DurableTask.ServiceFabric/ActivitiesProvider.cs new file mode 100644 index 000000000..99cea456c --- /dev/null +++ b/DurableTask.ServiceFabric/ActivitiesProvider.cs @@ -0,0 +1,81 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace DurableTask.ServiceFabric +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Threading; + using System.Threading.Tasks; + using Microsoft.ServiceFabric.Data; + using Microsoft.ServiceFabric.Data.Collections; + + class ActivitiesProvider + { + IReliableStateManager stateManager; + IReliableQueue activityQueue; + + public ActivitiesProvider(IReliableStateManager stateManager, IReliableQueue activityQueue) + { + if (stateManager == null) + { + throw new ArgumentNullException(nameof(stateManager)); + } + + if (activityQueue == null) + { + throw new ArgumentNullException(nameof(activityQueue)); + } + + this.stateManager = stateManager; + this.activityQueue = activityQueue; + } + + public async Task GetNextWorkItem(TimeSpan receiveTimeout, CancellationToken cancellationToken) + { + Stopwatch timer = Stopwatch.StartNew(); + while (timer.Elapsed < receiveTimeout && !cancellationToken.IsCancellationRequested) + { + using (var txn = this.stateManager.CreateTransaction()) + { + var activityValue = await this.activityQueue.TryPeekAsync(txn, LockMode.Default); + if (activityValue.HasValue) + { + return activityValue.Value; + } + //Todo: Need commit here? + } + await Task.Delay(100, cancellationToken); + } + return null; + } + + //Todo: Should this use the same transaction instance as the above method? + // Currently the second parameter is ignored in implementation because it's expected that + // this method gets a call synchronously with the above method. When that changes, the implementation + // has to change accordingly. + public Task CompleteWorkItem(ITransaction transaction, TaskMessage message) + { + return this.activityQueue.TryDequeueAsync(transaction); + } + + public async Task AppendBatch(ITransaction transaction, IList messages) + { + foreach (var message in messages) + { + await this.activityQueue.EnqueueAsync(transaction, message); + } + } + } +} diff --git a/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index ca804b3d2..259a506f6 100644 --- a/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -79,6 +79,7 @@ + diff --git a/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 8b9e2d319..b34e73660 100644 --- a/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -31,7 +31,7 @@ public class FabricOrchestrationService : IOrchestrationService IOrchestrationServiceInstanceStore instanceStore; SessionsProvider orchestrationProvider; - IReliableQueue activities; + ActivitiesProvider activitiesProvider; PersistentSession currentSession; TaskMessage currentActivity; @@ -49,9 +49,9 @@ public FabricOrchestrationService(IReliableStateManager stateManager, IOrchestra public async Task StartAsync() { - //Todo: Need to abstract the worker queue to it's own class like SessionsProvider - this.activities = await this.stateManager.GetOrAddAsync>(Constants.ActivitiesQueueName); + var activities = await this.stateManager.GetOrAddAsync>(Constants.ActivitiesQueueName); var orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); + this.activitiesProvider = new ActivitiesProvider(this.stateManager, activities); this.orchestrationProvider = new SessionsProvider(stateManager, orchestrations); } @@ -73,11 +73,11 @@ public Task CreateAsync() public async Task CreateAsync(bool recreateInstanceStore) { await DeleteAsync(deleteInstanceStore: recreateInstanceStore); + // Actual creation will be done on demand when we call GetOrAddAsync in StartAsync method. } public Task CreateIfNotExistsAsync() { - // This is not really needed because of winfab API which allows us to GetOrAdd return Task.FromResult(null); } @@ -88,7 +88,6 @@ public Task DeleteAsync() public async Task DeleteAsync(bool deleteInstanceStore) { - //Todo: Do we need a transaction for this? await this.stateManager.RemoveAsync(Constants.OrchestrationDictionaryName); await this.stateManager.RemoveAsync(Constants.ActivitiesQueueName); } @@ -177,16 +176,12 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( using (var txn = this.stateManager.CreateTransaction()) { - foreach (var workerMessage in outboundMessages) - { - await this.activities.EnqueueAsync(txn, workerMessage); - } - + await this.activitiesProvider.AppendBatch(txn, outboundMessages); await this.orchestrationProvider.CompleteSessionMessagesAsync(txn, this.currentSession, newOrchestrationRuntimeState); + // Todo: This is not yet part of the transaction if (this.instanceStore != null) { - // Todo: This is not yet part of the transaction await this.instanceStore.WriteEntitesAsync(new InstanceEntityBase[] { new OrchestrationStateInstanceEntity() @@ -221,13 +216,13 @@ public async Task LockNextTaskActivityWorkItem(TimeSpan re { Contract.Assert(this.currentActivity == null, "How come we get a call for another activity while an activity is running?"); - this.currentActivity = await this.GetNextWorkItem(receiveTimeout, cancellationToken); + this.currentActivity = await this.activitiesProvider.GetNextWorkItem(receiveTimeout, cancellationToken); if (this.currentActivity != null) { return new TaskActivityWorkItem() { - Id = "N/A", //Todo: Need to persist the guid?? + Id = Guid.NewGuid().ToString(), //Todo: Do we need to persist this in activity queue? TaskMessage = this.currentActivity }; } @@ -235,33 +230,13 @@ public async Task LockNextTaskActivityWorkItem(TimeSpan re return null; } - async Task GetNextWorkItem(TimeSpan receiveTimeout, CancellationToken cancellationToken) - { - Stopwatch timer = Stopwatch.StartNew(); - while (timer.Elapsed < receiveTimeout && !cancellationToken.IsCancellationRequested) - { - using (var txn = this.stateManager.CreateTransaction()) - { - var activityValue = await this.activities.TryPeekAsync(txn, LockMode.Default); - if (activityValue.HasValue) - { - return activityValue.Value; - } - //Todo: Need commit here? - } - await Task.Delay(100, cancellationToken); - } - return null; - } - - //Todo: Should this use the same transaction instance as the above method? public async Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workItem, TaskMessage responseMessage) { Contract.Assert(workItem.TaskMessage == this.currentActivity, "Unexpected thing happened, complete called for an activity that's not the current activity"); using (var txn = this.stateManager.CreateTransaction()) { - await this.activities.TryDequeueAsync(txn); + await this.activitiesProvider.CompleteWorkItem(txn, workItem.TaskMessage); var sessionId = workItem.TaskMessage.OrchestrationInstance.InstanceId; await this.orchestrationProvider.AppendMessageAsync(txn, sessionId, responseMessage); await txn.CommitAsync(); @@ -271,6 +246,7 @@ public async Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workIte public Task AbandonTaskActivityWorkItemAsync(TaskActivityWorkItem workItem) { + Contract.Assert(workItem.TaskMessage == this.currentActivity, "Unexpected thing happened, abandon called for an activity that's not the current activity"); this.currentActivity = null; return Task.FromResult(workItem); } diff --git a/DurableTask.ServiceFabric/SessionsProvider.cs b/DurableTask.ServiceFabric/SessionsProvider.cs index 50f8ed3c1..d6d3c1500 100644 --- a/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/DurableTask.ServiceFabric/SessionsProvider.cs @@ -23,7 +23,7 @@ namespace DurableTask.ServiceFabric using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; - public class SessionsProvider + class SessionsProvider { IReliableStateManager stateManager; IReliableDictionary orchestrations; @@ -35,6 +35,11 @@ public SessionsProvider(IReliableStateManager stateManager, IReliableDictionary< throw new ArgumentNullException(nameof(stateManager)); } + if (orchestrations == null) + { + throw new ArgumentNullException(nameof(orchestrations)); + } + this.stateManager = stateManager; this.orchestrations = orchestrations; } From b1e879d0915373d881a61d399d4251931546fe53 Mon Sep 17 00:00:00 2001 From: pradeek Date: Thu, 18 Aug 2016 16:55:05 -0700 Subject: [PATCH 013/210] Deleting the protoype in memory implementation used to initially to seed for service fabric implementation. --- .../PrototypeMocks/SessionDocument.cs | 67 --- .../PrototypeMocks/SessionsQueue.cs | 35 -- ...SynchronousInMemoryOrchestrationService.cs | 486 ------------------ .../DurableTaskCoreFxTest.cs | 4 +- .../DurableTask.ServiceBus.Tests.csproj | 3 - 5 files changed, 2 insertions(+), 593 deletions(-) delete mode 100644 FrameworkUnitTests/PrototypeMocks/SessionDocument.cs delete mode 100644 FrameworkUnitTests/PrototypeMocks/SessionsQueue.cs delete mode 100644 FrameworkUnitTests/PrototypeMocks/SynchronousInMemoryOrchestrationService.cs diff --git a/FrameworkUnitTests/PrototypeMocks/SessionDocument.cs b/FrameworkUnitTests/PrototypeMocks/SessionDocument.cs deleted file mode 100644 index 8158b84b4..000000000 --- a/FrameworkUnitTests/PrototypeMocks/SessionDocument.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using DurableTask; - -namespace FrameworkUnitTests.PrototypeMocks -{ - class SessionDocument - { - public string Id; - public byte[] SessionState; - readonly Queue Messages = new Queue(); - - object syncLock = new object(); - - public void AppendMessage(TaskMessage newMessage) - { - lock (syncLock) - { - Messages.Enqueue(new LockableTaskMessage() {TaskMessage = newMessage}); - } - } - - public bool AnyActiveMessages() - { - lock (syncLock) - { - return Messages.Any(); - } - } - - public List LockMessages() - { - var result = new List(); - lock (syncLock) - { - foreach (var m in this.Messages) - { - m.Locked = true; - result.Add(m.TaskMessage); - } - } - return result; - } - - public void CompleteLocked() - { - lock (syncLock) - { - while (Messages.Any()) - { - var m = Messages.Peek(); - if (!m.Locked) - { - return; - } - Messages.Dequeue(); - } - } - } - } - - class LockableTaskMessage - { - public TaskMessage TaskMessage; - public bool Locked; - } -} diff --git a/FrameworkUnitTests/PrototypeMocks/SessionsQueue.cs b/FrameworkUnitTests/PrototypeMocks/SessionsQueue.cs deleted file mode 100644 index a3dca9c45..000000000 --- a/FrameworkUnitTests/PrototypeMocks/SessionsQueue.cs +++ /dev/null @@ -1,35 +0,0 @@ -using DurableTask; - -namespace FrameworkUnitTests.PrototypeMocks -{ - class SessionsQueue - { - // Should create a session if one does not exist - // Should add to active messages of session - public void AppendMessage(TaskMessage message) - { - - } - - // Should return a session with some active messages - // all current messages should be marked for completion in complete call - public SessionDocument AcceptSession() - { - return null; - } - - // Needs to complete all messages which were given at AcceptSession time and delete them. - public void CompleteSession(SessionDocument session) - { - - } - - // Implementation requirement, since we are maintaining active sessions in a queue, - // complete takes out of it and returns, if there is no call to complete within a time - // (node crash) we should put the session back on the queue - private void ExpireSessionLock() - { - - } - } -} diff --git a/FrameworkUnitTests/PrototypeMocks/SynchronousInMemoryOrchestrationService.cs b/FrameworkUnitTests/PrototypeMocks/SynchronousInMemoryOrchestrationService.cs deleted file mode 100644 index 3309544bb..000000000 --- a/FrameworkUnitTests/PrototypeMocks/SynchronousInMemoryOrchestrationService.cs +++ /dev/null @@ -1,486 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics.Contracts; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using DurableTask; -using DurableTask.History; -using Newtonsoft.Json; - -namespace FrameworkUnitTests.PrototypeMocks -{ - class SynchronousInMemoryOrchestrationService : IOrchestrationService, IOrchestrationServiceClient - { - Queue _workerQueue = new Queue(); - Dictionary _orchestrationSessions = new Dictionary(); - - Dictionary> _instanceStore = new Dictionary>(); - ConcurrentDictionary> _orchestrationWaiters = new ConcurrentDictionary>(); - CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); - - SessionDocument _peekedSession = null; - TaskMessage _peekedActivity = null; - - object _thisLock = new object(); - - public Task StartAsync() - { - return Task.FromResult(null); - } - - public Task StopAsync() - { - return StopAsync(false); - } - - public Task StopAsync(bool isForced) - { - this._cancellationTokenSource.Cancel(); - return Task.FromResult(null); - } - - public Task CreateAsync() - { - return CreateAsync(true); - } - - public Task CreateAsync(bool recreateInstanceStore) - { - return Task.FromResult(null); - } - - public Task CreateIfNotExistsAsync() - { - return Task.FromResult(null); - } - - public Task DeleteAsync() - { - return DeleteAsync(true); - } - - public Task DeleteAsync(bool deleteInstanceStore) - { - return Task.FromResult(null); - } - - public bool IsMaxMessageCountExceeded(int currentMessageCount, OrchestrationRuntimeState runtimeState) - { - return false; - } - - public int GetDelayInSecondsAfterOnProcessException(Exception exception) - { - return 0; - } - - public int GetDelayInSecondsAfterOnFetchException(Exception exception) - { - return 0; - } - - public int TaskOrchestrationDispatcherCount => 1; - public int MaxConcurrentTaskOrchestrationWorkItems => 1; - public Task LockNextTaskOrchestrationWorkItemAsync(TimeSpan receiveTimeout, CancellationToken cancellationToken) - { - //lock (_thisLock) - { - Contract.Assert(_peekedSession == null, "How come we get a call for another session while a session is being processed?"); - - // Todo: This is the bad part - this really is a look up for the first session with no lock and some messages to process and it requires O(n) of dictionary - foreach (var entry in _orchestrationSessions) - { - if (!entry.Value.AnyActiveMessages()) - { - continue; - } - - _peekedSession = entry.Value; - - return Task.FromResult(new TaskOrchestrationWorkItem() - { - NewMessages = _peekedSession.LockMessages(), - InstanceId = _peekedSession.Id, - OrchestrationRuntimeState = - this.DeserializeOrchestrationRuntimeState(_peekedSession.SessionState) ?? - new OrchestrationRuntimeState() - }); - } - } - - return Task.FromResult(null); - } - - public Task RenewTaskOrchestrationWorkItemLockAsync(TaskOrchestrationWorkItem workItem) - { - throw new NotImplementedException(); - } - - public Task CompleteTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkItem workItem, - OrchestrationRuntimeState newOrchestrationRuntimeState, - IList outboundMessages, - IList orchestratorMessages, - IList timerMessages, - TaskMessage continuedAsNewMessage, - OrchestrationState orchestrationState) - { - Contract.Assert(string.Equals(_peekedSession.Id, workItem.InstanceId), "Unexpected thing happened, complete should be called with the same session as locked"); - - //if (timerMessages != null) - //{ - // throw new ArgumentException("timer messages not supported"); - //} - - //if (orchestratorMessages != null) - //{ - // throw new ArgumentException("Sub orchestrations are not supported"); - //} - - //if (continuedAsNewMessage != null) - //{ - // throw new ArgumentException("Continued as new is not supported"); - //} - - lock (_thisLock) - { - _peekedSession.SessionState = this.SerializeOrchestrationRuntimeState(newOrchestrationRuntimeState); - - foreach (var m in outboundMessages) - { - _workerQueue.Enqueue(m); - } - - _peekedSession.CompleteLocked(); - var state = orchestrationState; - _peekedSession = null; - if (state != null) - { - Dictionary ed; - - if (!this._instanceStore.TryGetValue(workItem.InstanceId, out ed)) - { - ed = new Dictionary(); - this._instanceStore[workItem.InstanceId] = ed; - } - - ed[workItem.OrchestrationRuntimeState.OrchestrationInstance.ExecutionId] = state; - - // signal any waiters waiting on instanceid_executionid or just the latest instanceid_ - TaskCompletionSource tcs = null; - TaskCompletionSource tcs1 = null; - - if (state.OrchestrationStatus == OrchestrationStatus.Running - || state.OrchestrationStatus == OrchestrationStatus.Pending) - { - return Task.FromResult(0); - } - - string key = workItem.OrchestrationRuntimeState.OrchestrationInstance.InstanceId + "_" + - workItem.OrchestrationRuntimeState.OrchestrationInstance.ExecutionId; - - string key1 = workItem.OrchestrationRuntimeState.OrchestrationInstance.InstanceId + "_"; - - var tasks = new List(); - - - if (this._orchestrationWaiters.TryGetValue(key, out tcs)) - { - tasks.Add(Task.Run(() => tcs.TrySetResult(state))); - } - - // for instanceid level waiters, we will not consider continueasnew as a terminal state because - // the high level orch is still ongoing - if (state.OrchestrationStatus != OrchestrationStatus.ContinuedAsNew - && this._orchestrationWaiters.TryGetValue(key1, out tcs1)) - { - tasks.Add(Task.Run(() => tcs1.TrySetResult(state))); - } - - if (tasks.Count > 0) - { - Task.WaitAll(tasks.ToArray()); - } - } - - } - - return Task.FromResult(null); - } - - public Task AbandonTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkItem workItem) - { - //lock (_thisLock) - { - _peekedSession = null; - } - return Task.FromResult(null); - } - - public Task ReleaseTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkItem workItem) - { - return Task.FromResult(null); - } - - public int TaskActivityDispatcherCount => 1; - public int MaxConcurrentTaskActivityWorkItems => 1; - - public Task LockNextTaskActivityWorkItem(TimeSpan receiveTimeout, CancellationToken cancellationToken) - { - Contract.Assert(_peekedActivity == null, "How come we get a call for another activity while an activity is running?"); - - //lock (_thisLock) - { - if (!_workerQueue.Any()) return Task.FromResult(null); - - _peekedActivity = _workerQueue.Peek(); - } - - return Task.FromResult(new TaskActivityWorkItem() - { - Id = "N/A", - TaskMessage = _peekedActivity - }); - } - - public Task RenewTaskActivityWorkItemLockAsync(TaskActivityWorkItem workItem) - { - Contract.Assert(workItem.TaskMessage == _peekedActivity, "Unexpected thing happened, renew lock called for an activity that's not the current activity"); - return Task.FromResult(workItem); - } - - public Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workItem, TaskMessage responseMessage) - { - Contract.Assert(workItem.TaskMessage == _peekedActivity, "Unexpected thing happened, complete called for an activity that's not the current activity"); - - lock (_thisLock) - { - var sessionId = workItem.TaskMessage.OrchestrationInstance.InstanceId; - _orchestrationSessions[sessionId].AppendMessage(responseMessage); - _workerQueue.Dequeue(); - _peekedActivity = null; - } - - return Task.FromResult(null); - } - - public Task AbandonTaskActivityWorkItemAsync(TaskActivityWorkItem workItem) - { - //lock (_thisLock) - { - _peekedActivity = null; - } - return Task.FromResult(workItem); - } - - byte[] SerializeOrchestrationRuntimeState(OrchestrationRuntimeState runtimeState) - { - if (runtimeState == null) - { - return null; - } - - string serializeState = JsonConvert.SerializeObject(runtimeState.Events, - new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); - return Encoding.UTF8.GetBytes(serializeState); - } - - OrchestrationRuntimeState DeserializeOrchestrationRuntimeState(byte[] stateBytes) - { - if (stateBytes == null || stateBytes.Length == 0) - { - return null; - } - - string serializedState = Encoding.UTF8.GetString(stateBytes); - IList events = JsonConvert.DeserializeObject>(serializedState, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }); - return new OrchestrationRuntimeState(events); - } - - /******************************/ - // client methods - /******************************/ - - public Task CreateTaskOrchestrationAsync(TaskMessage creationMessage) - { - ExecutionStartedEvent ee = creationMessage.Event as ExecutionStartedEvent; - - if (ee == null) - { - throw new InvalidOperationException("Invalid creation task message"); - } - - lock (this._thisLock) - { - SessionDocument session; - if (!_orchestrationSessions.TryGetValue(creationMessage.OrchestrationInstance.InstanceId, out session)) - { - _orchestrationSessions.Add(creationMessage.OrchestrationInstance.InstanceId, new SessionDocument() - { - Id = creationMessage.OrchestrationInstance.InstanceId, - SessionState = this.SerializeOrchestrationRuntimeState(new OrchestrationRuntimeState()) - }); - } - _orchestrationSessions[creationMessage.OrchestrationInstance.InstanceId].AppendMessage(creationMessage); - - Dictionary ed; - - if (!this._instanceStore.TryGetValue(creationMessage.OrchestrationInstance.InstanceId, out ed)) - { - ed = new Dictionary(); - this._instanceStore[creationMessage.OrchestrationInstance.InstanceId] = ed; - } - - OrchestrationState newState = new OrchestrationState() - { - OrchestrationInstance = new OrchestrationInstance - { - InstanceId = creationMessage.OrchestrationInstance.InstanceId, - ExecutionId = creationMessage.OrchestrationInstance.ExecutionId, - }, - CreatedTime = DateTime.UtcNow, - OrchestrationStatus = OrchestrationStatus.Pending, - Version = ee.Version, - Name = ee.Name, - Input = ee.Input, - }; - - ed.Add(creationMessage.OrchestrationInstance.ExecutionId, newState); - } - - return Task.FromResult(null); - } - - public Task SendTaskOrchestrationMessageAsync(TaskMessage message) - { - throw new NotImplementedException(); - } - - public async Task WaitForOrchestrationAsync(string instanceId, string executionId, TimeSpan timeout, CancellationToken cancellationToken) - { - if (string.IsNullOrWhiteSpace(executionId)) - { - executionId = string.Empty; - } - - string key = instanceId + "_" + executionId; - - TaskCompletionSource tcs = null; - if (!this._orchestrationWaiters.TryGetValue(key, out tcs)) - { - tcs = new TaskCompletionSource(); - - if (!this._orchestrationWaiters.TryAdd(key, tcs)) - { - this._orchestrationWaiters.TryGetValue(key, out tcs); - } - - if (tcs == null) - { - throw new InvalidOperationException("Unable to get tcs from orchestrationWaiters"); - } - } - - // might have finished already - lock (this._thisLock) - { - if (this._instanceStore.ContainsKey(instanceId)) - { - Dictionary emap = this._instanceStore[instanceId]; - - if (emap != null && emap.Count > 0) - { - OrchestrationState state = null; - if (string.IsNullOrWhiteSpace(executionId)) - { - IOrderedEnumerable sortedemap = emap.Values.OrderByDescending(os => os.CreatedTime); - state = sortedemap.First(); - } - else - { - if (emap.ContainsKey(executionId)) - { - state = this._instanceStore[instanceId][executionId]; - } - } - - if (state != null - && state.OrchestrationStatus != OrchestrationStatus.Running - && state.OrchestrationStatus != OrchestrationStatus.Pending) - { - // if only master id was specified then continueasnew is a not a terminal state - if (!(string.IsNullOrWhiteSpace(executionId) && state.OrchestrationStatus == OrchestrationStatus.ContinuedAsNew)) - { - tcs.TrySetResult(state); - } - } - } - } - } - - var cts = CancellationTokenSource.CreateLinkedTokenSource( - cancellationToken, - this._cancellationTokenSource.Token); - Task timeOutTask = Task.Delay(timeout, cts.Token); - Task ret = await Task.WhenAny(tcs.Task, timeOutTask); - - if (ret == timeOutTask) - { - throw new TimeoutException("timed out or canceled while waiting for orchestration to complete"); - } - - cts.Cancel(); - - return await tcs.Task; - } - - public Task ForceTerminateTaskOrchestrationAsync(string instanceId, string reason) - { - throw new NotImplementedException(); - } - - public async Task> GetOrchestrationStateAsync(string instanceId, bool allExecutions) - { - IList response = null; - lock (this._thisLock) - { - if (this._instanceStore[instanceId] != null) - { - response = this._instanceStore[instanceId].Values.ToList(); - } - else - { - response = new List(); - } - } - - return await Task.FromResult(response); - } - - public async Task GetOrchestrationStateAsync(string instanceId, string executionId) - { - OrchestrationState response = null; - lock (this._thisLock) - { - if (this._instanceStore[instanceId] != null) - { - response = this._instanceStore[instanceId][executionId]; - } - } - - return await Task.FromResult(response); - } - - public Task GetOrchestrationHistoryAsync(string instanceId, string executionId) - { - throw new NotImplementedException(); - } - - public Task PurgeOrchestrationHistoryAsync(DateTime thresholdDateTimeUtc, OrchestrationStateTimeRangeFilterType timeRangeFilterType) - { - throw new NotImplementedException(); - } - } -} diff --git a/test/DurableTask.Framework.Tests/DurableTaskCoreFxTest.cs b/test/DurableTask.Framework.Tests/DurableTaskCoreFxTest.cs index bddfc18b0..057bc61cc 100644 --- a/test/DurableTask.Framework.Tests/DurableTaskCoreFxTest.cs +++ b/test/DurableTask.Framework.Tests/DurableTaskCoreFxTest.cs @@ -45,7 +45,7 @@ public void TestCleanup() [TestMethod] public async Task MockOrchestrationTest() { - SynchronousInMemoryOrchestrationService orchService = new SynchronousInMemoryOrchestrationService(); + LocalOrchestrationService orchService = new LocalOrchestrationService(); TaskHubWorker worker = new TaskHubWorker(orchService); @@ -57,7 +57,7 @@ await worker.AddTaskOrchestrations(typeof(SimplestGreetingsOrchestration)) OrchestrationInstance id = await client.CreateOrchestrationInstanceAsync(typeof(SimplestGreetingsOrchestration), null); - OrchestrationState result = await client.WaitForOrchestrationAsync(id, TimeSpan.FromSeconds(600), new CancellationToken()); + OrchestrationState result = await client.WaitForOrchestrationAsync(id, TimeSpan.FromSeconds(30), new CancellationToken()); Assert.AreEqual(OrchestrationStatus.Completed, result.OrchestrationStatus); Assert.AreEqual("Greeting send to Gabbar", SimplestGreetingsOrchestration.Result, diff --git a/test/DurableTask.ServiceBus.Tests/DurableTask.ServiceBus.Tests.csproj b/test/DurableTask.ServiceBus.Tests/DurableTask.ServiceBus.Tests.csproj index 1466e3031..417d2755a 100644 --- a/test/DurableTask.ServiceBus.Tests/DurableTask.ServiceBus.Tests.csproj +++ b/test/DurableTask.ServiceBus.Tests/DurableTask.ServiceBus.Tests.csproj @@ -122,9 +122,6 @@ - - - From 1e98fe8006f43d081140664bee0dc30f27fe111f Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 19 Aug 2016 16:43:26 -0700 Subject: [PATCH 014/210] Moving the project folders according to the latest convention. --- .../DurableTask.ServiceFabric.Test.csproj | 0 .../DurableTask.ServiceFabric.Test}/Properties/AssemblyInfo.cs | 0 .../DurableTask.ServiceFabric.Test}/app.config | 0 .../DurableTask.ServiceFabric}/ActivitiesProvider.cs | 0 .../DurableTask.ServiceFabric}/Constants.cs | 0 .../DurableTask.ServiceFabric}/DurableTask.ServiceFabric.csproj | 0 .../FabricOrchestrationInstanceStore.cs | 0 .../DurableTask.ServiceFabric}/FabricOrchestrationService.cs | 0 .../FabricOrchestrationServiceClient.cs | 0 .../DurableTask.ServiceFabric}/FabricStatefulService.cs | 0 .../DurableTask.ServiceFabric}/PersistentSession.cs | 0 .../DurableTask.ServiceFabric}/Properties/AssemblyInfo.cs | 0 .../DurableTask.ServiceFabric}/SessionsProvider.cs | 0 .../DurableTask.ServiceFabric}/app.config | 0 .../DurableTask.ServiceFabric}/packages.config | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename {DurableTask.ServiceFabric.Test => Test/DurableTask.ServiceFabric.Test}/DurableTask.ServiceFabric.Test.csproj (100%) rename {DurableTask.ServiceFabric.Test => Test/DurableTask.ServiceFabric.Test}/Properties/AssemblyInfo.cs (100%) rename {DurableTask.ServiceFabric.Test => Test/DurableTask.ServiceFabric.Test}/app.config (100%) rename {DurableTask.ServiceFabric => src/DurableTask.ServiceFabric}/ActivitiesProvider.cs (100%) rename {DurableTask.ServiceFabric => src/DurableTask.ServiceFabric}/Constants.cs (100%) rename {DurableTask.ServiceFabric => src/DurableTask.ServiceFabric}/DurableTask.ServiceFabric.csproj (100%) rename {DurableTask.ServiceFabric => src/DurableTask.ServiceFabric}/FabricOrchestrationInstanceStore.cs (100%) rename {DurableTask.ServiceFabric => src/DurableTask.ServiceFabric}/FabricOrchestrationService.cs (100%) rename {DurableTask.ServiceFabric => src/DurableTask.ServiceFabric}/FabricOrchestrationServiceClient.cs (100%) rename {DurableTask.ServiceFabric => src/DurableTask.ServiceFabric}/FabricStatefulService.cs (100%) rename {DurableTask.ServiceFabric => src/DurableTask.ServiceFabric}/PersistentSession.cs (100%) rename {DurableTask.ServiceFabric => src/DurableTask.ServiceFabric}/Properties/AssemblyInfo.cs (100%) rename {DurableTask.ServiceFabric => src/DurableTask.ServiceFabric}/SessionsProvider.cs (100%) rename {DurableTask.ServiceFabric => src/DurableTask.ServiceFabric}/app.config (100%) rename {DurableTask.ServiceFabric => src/DurableTask.ServiceFabric}/packages.config (100%) diff --git a/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj b/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj similarity index 100% rename from DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj rename to Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj diff --git a/DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs b/Test/DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs similarity index 100% rename from DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs rename to Test/DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs diff --git a/DurableTask.ServiceFabric.Test/app.config b/Test/DurableTask.ServiceFabric.Test/app.config similarity index 100% rename from DurableTask.ServiceFabric.Test/app.config rename to Test/DurableTask.ServiceFabric.Test/app.config diff --git a/DurableTask.ServiceFabric/ActivitiesProvider.cs b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs similarity index 100% rename from DurableTask.ServiceFabric/ActivitiesProvider.cs rename to src/DurableTask.ServiceFabric/ActivitiesProvider.cs diff --git a/DurableTask.ServiceFabric/Constants.cs b/src/DurableTask.ServiceFabric/Constants.cs similarity index 100% rename from DurableTask.ServiceFabric/Constants.cs rename to src/DurableTask.ServiceFabric/Constants.cs diff --git a/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj similarity index 100% rename from DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj rename to src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj diff --git a/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs similarity index 100% rename from DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs rename to src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs diff --git a/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs similarity index 100% rename from DurableTask.ServiceFabric/FabricOrchestrationService.cs rename to src/DurableTask.ServiceFabric/FabricOrchestrationService.cs diff --git a/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs similarity index 100% rename from DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs rename to src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs diff --git a/DurableTask.ServiceFabric/FabricStatefulService.cs b/src/DurableTask.ServiceFabric/FabricStatefulService.cs similarity index 100% rename from DurableTask.ServiceFabric/FabricStatefulService.cs rename to src/DurableTask.ServiceFabric/FabricStatefulService.cs diff --git a/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs similarity index 100% rename from DurableTask.ServiceFabric/PersistentSession.cs rename to src/DurableTask.ServiceFabric/PersistentSession.cs diff --git a/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs b/src/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs similarity index 100% rename from DurableTask.ServiceFabric/Properties/AssemblyInfo.cs rename to src/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs diff --git a/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs similarity index 100% rename from DurableTask.ServiceFabric/SessionsProvider.cs rename to src/DurableTask.ServiceFabric/SessionsProvider.cs diff --git a/DurableTask.ServiceFabric/app.config b/src/DurableTask.ServiceFabric/app.config similarity index 100% rename from DurableTask.ServiceFabric/app.config rename to src/DurableTask.ServiceFabric/app.config diff --git a/DurableTask.ServiceFabric/packages.config b/src/DurableTask.ServiceFabric/packages.config similarity index 100% rename from DurableTask.ServiceFabric/packages.config rename to src/DurableTask.ServiceFabric/packages.config From 4cd2c86f5ee2aa253a85cb0432895b6df9295657 Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 19 Aug 2016 16:47:56 -0700 Subject: [PATCH 015/210] Fixing up sln files and project references for the new dir structure. --- DurableTask.ServiceFabric.sln | 79 ++++++++----------- .../DurableTask.ServiceFabric.Test.csproj | 2 +- .../TestStatefulService.csproj | 10 +-- .../DurableTask.ServiceFabric.csproj | 2 +- 4 files changed, 41 insertions(+), 52 deletions(-) diff --git a/DurableTask.ServiceFabric.sln b/DurableTask.ServiceFabric.sln index 0d29c59fb..bd217f93a 100644 --- a/DurableTask.ServiceFabric.sln +++ b/DurableTask.ServiceFabric.sln @@ -3,10 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTaskFramework", "Framework\DurableTaskFramework.csproj", "{6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTaskFrameworkUnitTests", "FrameworkUnitTests\DurableTaskFrameworkUnitTests.csproj", "{6639DA74-9063-4A7C-9484-0A71C4FB5C18}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{501E1168-418C-4832-B88C-617735BD02C9}" ProjectSection(SolutionItems) = preProject .nuget\NuGet.Config = .nuget\NuGet.Config @@ -14,11 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{501E11 .nuget\NuGet.targets = .nuget\NuGet.targets EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.ServiceFabric", "DurableTask.ServiceFabric\DurableTask.ServiceFabric.csproj", "{5C617B24-4902-4992-8F71-AB14F00B74A8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.ServiceFabric.Test", "DurableTask.ServiceFabric.Test\DurableTask.ServiceFabric.Test.csproj", "{EDC63DDB-8397-4AEC-BF54-6395B2527075}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Product", "Product", "{0AE737F5-4AA1-402F-A61C-258CA00E282C}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0AE737F5-4AA1-402F-A61C-258CA00E282C}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{5177D1DE-AC86-41B9-8D04-41988A7C2208}" EndProject @@ -30,6 +22,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestStatefulService", "Test EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication.Common", "Test\TestFabricApplication\TestApplication.Common\TestApplication.Common.csproj", "{EA90334D-3194-4266-81EB-EECA9C760315}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.ServiceFabric", "src\DurableTask.ServiceFabric\DurableTask.ServiceFabric.csproj", "{5C617B24-4902-4992-8F71-AB14F00B74A8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.Framework", "src\DurableTask.Framework\DurableTask.Framework.csproj", "{6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.ServiceFabric.Test", "Test\DurableTask.ServiceFabric.Test\DurableTask.ServiceFabric.Test.csproj", "{EDC63DDB-8397-4AEC-BF54-6395B2527075}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -38,38 +36,6 @@ Global Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Debug|x64.ActiveCfg = Debug|Any CPU - {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Debug|x64.Build.0 = Debug|Any CPU - {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Release|Any CPU.Build.0 = Release|Any CPU - {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Release|x64.ActiveCfg = Release|Any CPU - {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Release|x64.Build.0 = Release|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Debug|x64.ActiveCfg = Debug|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Debug|x64.Build.0 = Debug|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Release|Any CPU.Build.0 = Release|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Release|x64.ActiveCfg = Release|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Release|x64.Build.0 = Release|Any CPU - {5C617B24-4902-4992-8F71-AB14F00B74A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5C617B24-4902-4992-8F71-AB14F00B74A8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5C617B24-4902-4992-8F71-AB14F00B74A8}.Debug|x64.ActiveCfg = Debug|Any CPU - {5C617B24-4902-4992-8F71-AB14F00B74A8}.Debug|x64.Build.0 = Debug|Any CPU - {5C617B24-4902-4992-8F71-AB14F00B74A8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5C617B24-4902-4992-8F71-AB14F00B74A8}.Release|Any CPU.Build.0 = Release|Any CPU - {5C617B24-4902-4992-8F71-AB14F00B74A8}.Release|x64.ActiveCfg = Release|Any CPU - {5C617B24-4902-4992-8F71-AB14F00B74A8}.Release|x64.Build.0 = Release|Any CPU - {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Debug|x64.ActiveCfg = Debug|Any CPU - {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Debug|x64.Build.0 = Debug|Any CPU - {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Release|Any CPU.Build.0 = Release|Any CPU - {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Release|x64.ActiveCfg = Release|Any CPU - {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Release|x64.Build.0 = Release|Any CPU {CA924781-AE52-45FA-A817-C39C822FB782}.Debug|Any CPU.ActiveCfg = Debug|x64 {CA924781-AE52-45FA-A817-C39C822FB782}.Debug|x64.ActiveCfg = Debug|x64 {CA924781-AE52-45FA-A817-C39C822FB782}.Debug|x64.Build.0 = Debug|x64 @@ -92,19 +58,42 @@ Global {EA90334D-3194-4266-81EB-EECA9C760315}.Release|Any CPU.Build.0 = Release|Any CPU {EA90334D-3194-4266-81EB-EECA9C760315}.Release|x64.ActiveCfg = Release|Any CPU {EA90334D-3194-4266-81EB-EECA9C760315}.Release|x64.Build.0 = Release|Any CPU + {5C617B24-4902-4992-8F71-AB14F00B74A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5C617B24-4902-4992-8F71-AB14F00B74A8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5C617B24-4902-4992-8F71-AB14F00B74A8}.Debug|x64.ActiveCfg = Debug|Any CPU + {5C617B24-4902-4992-8F71-AB14F00B74A8}.Debug|x64.Build.0 = Debug|Any CPU + {5C617B24-4902-4992-8F71-AB14F00B74A8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5C617B24-4902-4992-8F71-AB14F00B74A8}.Release|Any CPU.Build.0 = Release|Any CPU + {5C617B24-4902-4992-8F71-AB14F00B74A8}.Release|x64.ActiveCfg = Release|Any CPU + {5C617B24-4902-4992-8F71-AB14F00B74A8}.Release|x64.Build.0 = Release|Any CPU + {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Debug|x64.ActiveCfg = Debug|Any CPU + {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Debug|x64.Build.0 = Debug|Any CPU + {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Release|Any CPU.Build.0 = Release|Any CPU + {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Release|x64.ActiveCfg = Release|Any CPU + {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37}.Release|x64.Build.0 = Release|Any CPU + {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Debug|x64.ActiveCfg = Debug|Any CPU + {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Debug|x64.Build.0 = Debug|Any CPU + {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Release|Any CPU.Build.0 = Release|Any CPU + {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Release|x64.ActiveCfg = Release|Any CPU + {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37} = {0AE737F5-4AA1-402F-A61C-258CA00E282C} - {6639DA74-9063-4A7C-9484-0A71C4FB5C18} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} - {5C617B24-4902-4992-8F71-AB14F00B74A8} = {0AE737F5-4AA1-402F-A61C-258CA00E282C} - {EDC63DDB-8397-4AEC-BF54-6395B2527075} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} {507C0CC2-082F-4EB7-8984-E2648976EB04} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} {CA924781-AE52-45FA-A817-C39C822FB782} = {507C0CC2-082F-4EB7-8984-E2648976EB04} {95D6C9C7-F7A0-4125-840D-1854BEC24978} = {507C0CC2-082F-4EB7-8984-E2648976EB04} {EA90334D-3194-4266-81EB-EECA9C760315} = {507C0CC2-082F-4EB7-8984-E2648976EB04} + {5C617B24-4902-4992-8F71-AB14F00B74A8} = {0AE737F5-4AA1-402F-A61C-258CA00E282C} + {6F5D2EAD-726D-4FE5-A575-AEB96D1CCE37} = {0AE737F5-4AA1-402F-A61C-258CA00E282C} + {EDC63DDB-8397-4AEC-BF54-6395B2527075} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EnterpriseLibraryConfigurationToolBinariesPath = packages\TransientFaultHandling.Core.5.1.1209.1\lib\NET4 diff --git a/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj b/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj index 5113314f4..8afb490a0 100644 --- a/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj +++ b/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj @@ -44,7 +44,7 @@ - + {5c617b24-4902-4992-8f71-ab14f00b74a8} DurableTask.ServiceFabric diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj index 9295f8d55..c38cb87c3 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj @@ -126,14 +126,14 @@ - + + {6f5d2ead-726d-4fe5-a575-aeb96d1cce37} + DurableTask.Framework + + {5c617b24-4902-4992-8f71-ab14f00b74a8} DurableTask.ServiceFabric - - {6f5d2ead-726d-4fe5-a575-aeb96d1cce37} - DurableTaskFramework - {ea90334d-3194-4266-81eb-eeca9c760315} TestApplication.Common diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 259a506f6..cb190ea4f 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -96,7 +96,7 @@ - + {6f5d2ead-726d-4fe5-a575-aeb96d1cce37} DurableTaskFramework From f063e1798281dfa80313bde168bcc09fff1d8e08 Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 19 Aug 2016 16:53:57 -0700 Subject: [PATCH 016/210] Fixing up package references in csproj to make it build. --- .../DurableTask.ServiceFabric.csproj | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index cb190ea4f..42a7e2e87 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -31,23 +31,15 @@ - ..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll + ..\..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll True - ..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll - True - - - ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.dll - True - - - ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll + ..\..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll True - ..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\Microsoft.ServiceFabric.Services.dll + ..\..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\Microsoft.ServiceFabric.Services.dll True @@ -56,7 +48,7 @@ True - ..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\ServiceFabricServiceModel.dll + ..\..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\ServiceFabricServiceModel.dll True From c7015e1755929ec37a01583ed97ab87088df3969 Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 19 Aug 2016 17:21:37 -0700 Subject: [PATCH 017/210] Fixing a bad merge. --- .../DurableTask.ServiceBus.Tests.csproj | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/DurableTask.ServiceBus.Tests/DurableTask.ServiceBus.Tests.csproj b/test/DurableTask.ServiceBus.Tests/DurableTask.ServiceBus.Tests.csproj index 417d2755a..f49d1b39c 100644 --- a/test/DurableTask.ServiceBus.Tests/DurableTask.ServiceBus.Tests.csproj +++ b/test/DurableTask.ServiceBus.Tests/DurableTask.ServiceBus.Tests.csproj @@ -122,11 +122,6 @@ - - - - - From 188ad08ae5af6cc895817193331e2fef4267df91 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 23 Aug 2016 09:50:03 -0700 Subject: [PATCH 018/210] Some implementation of timers that works for now. Perhaps it could be improved and also the code could be better organized? --- .gitignore | 1 + .../DebugHelper/TestExecutor.cs | 2 +- .../SimpleOrchestrationWithTimer.cs | 30 +++++++ .../TestStatefulService.cs | 3 +- .../TestStatefulService.csproj | 1 + .../FabricOrchestrationService.cs | 10 +-- .../FabricOrchestrationServiceClient.cs | 4 +- .../PersistentSession.cs | 79 +++++++++++++++++-- .../SessionsProvider.cs | 58 ++++++++++++-- 9 files changed, 168 insertions(+), 20 deletions(-) create mode 100644 Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTimer.cs diff --git a/.gitignore b/.gitignore index 823118b36..065b73083 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ bin/ obj/ packages/ +pkg/ TestResults/ sign.snk diff --git a/Test/TestFabricApplication/TestStatefulService/DebugHelper/TestExecutor.cs b/Test/TestFabricApplication/TestStatefulService/DebugHelper/TestExecutor.cs index a0f8e7a8d..ba7cf9664 100644 --- a/Test/TestFabricApplication/TestStatefulService/DebugHelper/TestExecutor.cs +++ b/Test/TestFabricApplication/TestStatefulService/DebugHelper/TestExecutor.cs @@ -34,7 +34,7 @@ public Task StartAsync() { var startTask = Task.Run(async () => { - var instance = await client.CreateOrchestrationInstanceAsync(typeof(SimpleOrchestrationWithTasks), input: null); + var instance = await client.CreateOrchestrationInstanceAsync(typeof(SimpleOrchestrationWithTimer), input: 37); var state = await client.WaitForOrchestrationAsync(instance, TimeSpan.FromMinutes(10)); var result = state.Output; }, this.cancellationTokenSource.Token); diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTimer.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTimer.cs new file mode 100644 index 000000000..072b0a326 --- /dev/null +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTimer.cs @@ -0,0 +1,30 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Threading.Tasks; +using DurableTask; + +namespace TestStatefulService.TestOrchestrations +{ + class SimpleOrchestrationWithTimer : TaskOrchestration + { + public override async Task RunTask(OrchestrationContext context, int input) + { + ServiceEventSource.Current.Message($"CurrentUtcDataTime before scheduling the timer and waiting : {context.CurrentUtcDateTime}"); + await context.CreateTimer(context.CurrentUtcDateTime.Add(TimeSpan.FromSeconds(input)), null); + ServiceEventSource.Current.Message($"CurrentUtcDataTime after finished waiting for the timer : {context.CurrentUtcDateTime}"); + return await context.ScheduleTask(typeof(GreetUserTask), "Gabbar"); + } + } +} diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index 153147348..75829bef4 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -66,7 +66,8 @@ protected override IEnumerable CreateServiceReplicaListe /// Canceled when Service Fabric needs to shut down this service replica. protected override async Task RunAsync(CancellationToken cancellationToken) { - await this.worker.AddTaskOrchestrations(typeof(SimpleOrchestrationWithTasks)) + await this.worker + .AddTaskOrchestrations(typeof(SimpleOrchestrationWithTasks), typeof(SimpleOrchestrationWithTimer)) .AddTaskActivities(typeof(GetUserTask), typeof(GreetUserTask)) .StartAsync(); diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj index c38cb87c3..a1078a0b9 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj @@ -113,6 +113,7 @@ + diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index b34e73660..014758f1b 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -53,6 +53,7 @@ public async Task StartAsync() var orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); this.activitiesProvider = new ActivitiesProvider(this.stateManager, activities); this.orchestrationProvider = new SessionsProvider(stateManager, orchestrations); + await this.orchestrationProvider.StartAsync(); } public Task StopAsync() @@ -62,6 +63,7 @@ public Task StopAsync() public Task StopAsync(bool isForced) { + this.orchestrationProvider.Stop(); return Task.FromResult(null); } @@ -159,11 +161,6 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( { Contract.Assert(this.currentSession != null && string.Equals(currentSession.SessionId, workItem.InstanceId), "Unexpected thing happened, complete should be called with the same session as locked"); - if (timerMessages != null && timerMessages.Count > 0) - { - throw new ArgumentException("timer messages not supported yet"); - } - if (orchestratorMessages != null && orchestratorMessages.Count > 0) { throw new ArgumentException("Sub orchestrations are not supported yet"); @@ -177,7 +174,8 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( using (var txn = this.stateManager.CreateTransaction()) { await this.activitiesProvider.AppendBatch(txn, outboundMessages); - await this.orchestrationProvider.CompleteSessionMessagesAsync(txn, this.currentSession, newOrchestrationRuntimeState); + + await this.orchestrationProvider.CompleteAndUpdateSession(txn, this.currentSession, newOrchestrationRuntimeState, timerMessages); // Todo: This is not yet part of the transaction if (this.instanceStore != null) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index c03e38a9d..fe26b4d84 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -55,10 +55,10 @@ public async Task SendTaskOrchestrationMessageAsync(TaskMessage message) var sessionId = message.OrchestrationInstance.InstanceId; //Todo: This is the same code as SessionsProvider.AppendMessages, can perhaps reuse somehow? - var newSession = new PersistentSession(sessionId, new OrchestrationRuntimeState(), new LockableTaskMessage() { TaskMessage = message }); + Func newSessionFactory = (sid) => new PersistentSession(sessionId, new OrchestrationRuntimeState(), new LockableTaskMessage() { TaskMessage = message }); await orchestrations.AddOrUpdateAsync(txn, sessionId, - addValue: newSession, + addValueFactory: newSessionFactory, updateValueFactory: (ses, oldValue) => oldValue.AppendMessage(message)); await txn.CommitAsync(); diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index 6d4d02bbc..0ce6d20b8 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -11,9 +11,12 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using System; using System.Runtime.Serialization; using System.Text; +using System.Threading.Tasks; using DurableTask.History; +using Microsoft.ServiceFabric.Data; using Newtonsoft.Json; namespace DurableTask.ServiceFabric @@ -28,15 +31,19 @@ public sealed class PersistentSession static readonly IEnumerable NoMessages = ImmutableList.Empty; public PersistentSession(string sessionId, OrchestrationRuntimeState sessionState, LockableTaskMessage message) - : this(sessionId, sessionState, new LockableTaskMessage[] { message}) + : this(sessionId, sessionState, new LockableTaskMessage[] {message}, null) { } - public PersistentSession(string sessionId, OrchestrationRuntimeState sessionState, IEnumerable messages) + public PersistentSession(string sessionId, + OrchestrationRuntimeState sessionState, + IEnumerable messages, + IEnumerable scheduledMessages) { this.SessionId = sessionId; this.SessionState = sessionState; this.Messages = messages != null ? messages.ToImmutableList() : NoMessages; + this.ScheduledMessages = scheduledMessages != null ? scheduledMessages.ToImmutableList() : NoMessages; } [DataMember] @@ -50,14 +57,76 @@ public PersistentSession(string sessionId, OrchestrationRuntimeState sessionStat [DataMember] public IEnumerable Messages { get; private set; } + [DataMember] + public IEnumerable ScheduledMessages { get; private set; } + public PersistentSession SetSessionState(OrchestrationRuntimeState newState) { - return new PersistentSession(this.SessionId, newState, this.Messages); + return new PersistentSession(this.SessionId, newState, this.Messages, this.ScheduledMessages); } public PersistentSession AppendMessage(TaskMessage message) { - return new PersistentSession(this.SessionId, this.SessionState, this.Messages.ToImmutableList().Add(new LockableTaskMessage() {TaskMessage = message})); + return new PersistentSession(this.SessionId, + this.SessionState, + this.Messages.ToImmutableList().Add(new LockableTaskMessage() {TaskMessage = message}), + this.ScheduledMessages); + } + + public PersistentSession AppendScheduledMessagesBatch(IEnumerable newMessages) + { + var scheduledMessages = this.ScheduledMessages.ToList(); + foreach (var message in newMessages) + { + if (!(message.Event is TimerFiredEvent)) + { + throw new ArgumentException("Expecting a scheduled message"); + } + scheduledMessages.Add(new LockableTaskMessage() { TaskMessage = message }); + } + return new PersistentSession(this.SessionId, this.SessionState, this.Messages, scheduledMessages); + } + + // Todo: Can optimize in a few other ways, for now, something that works + public bool CheckScheduledMessages(out PersistentSession newValue) + { + newValue = this; + if (!this.ScheduledMessages.Any()) + { + return false; + } + + bool changed = false; + var currentTime = DateTime.UtcNow; + var newMessages = this.Messages.ToList(); + var remainingScheduledMessages = new List(); + + foreach (var scheduledMessage in this.ScheduledMessages) + { + var timerEvent = scheduledMessage.TaskMessage.Event as TimerFiredEvent; + + if (timerEvent == null) + { + //Should not happen with the current assumptions + throw new Exception("Internal server errors"); + } + + if (timerEvent.FireAt <= currentTime) + { + newMessages.Add(scheduledMessage); + changed = true; + } + else + { + remainingScheduledMessages.Add(scheduledMessage); + } + } + + if (changed) + { + newValue = new PersistentSession(this.SessionId, this.SessionState, newMessages, remainingScheduledMessages); + } + return changed; } public List ReceiveMessages() @@ -76,7 +145,7 @@ public PersistentSession CompleteMessages() { //Todo: Need to be thread-safe? var newMessages = this.Messages.Where(m => !m.Received); - return new PersistentSession(this.SessionId, this.SessionState, newMessages); + return new PersistentSession(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages); } [OnDeserialized] diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index d6d3c1500..f4ce07fdb 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -27,6 +27,7 @@ class SessionsProvider { IReliableStateManager stateManager; IReliableDictionary orchestrations; + CancellationTokenSource cancellationTokenSource; public SessionsProvider(IReliableStateManager stateManager, IReliableDictionary orchestrations) { @@ -42,6 +43,42 @@ public SessionsProvider(IReliableStateManager stateManager, IReliableDictionary< this.stateManager = stateManager; this.orchestrations = orchestrations; + this.cancellationTokenSource = new CancellationTokenSource(); + } + + public Task StartAsync() + { + var nowait = Task.Run(async () => + { + while (!this.cancellationTokenSource.IsCancellationRequested) + { + await Task.Delay(TimeSpan.FromMilliseconds(100)); + using (var txn = this.stateManager.CreateTransaction()) + { + var enumerable = await this.orchestrations.CreateEnumerableAsync(txn, EnumerationMode.Unordered); + using (var enumerator = enumerable.GetAsyncEnumerator()) + { + while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) + { + var entry = enumerator.Current; + PersistentSession newValue; + if (entry.Value.CheckScheduledMessages(out newValue)) + { + await this.orchestrations.SetAsync(txn, entry.Key, newValue); //Is this valid code? Can enumeration update the value? + } + } + } + await txn.CommitAsync(); + } + } + }); + + return Task.FromResult(null); + } + + public void Stop() + { + this.cancellationTokenSource.Cancel(); } //Todo: This is O(N) and also a frequent operation, do we need to optimize this? @@ -80,19 +117,30 @@ public List GetSessionMessages(PersistentSession session) return session.ReceiveMessages(); } - public async Task CompleteSessionMessagesAsync(ITransaction transaction, PersistentSession session, OrchestrationRuntimeState newSessionState) + public async Task CompleteAndUpdateSession(ITransaction transaction, + PersistentSession session, + OrchestrationRuntimeState newSessionState, + IList scheduledMessages) { - var newSession = session.CompleteMessages().SetSessionState(newSessionState); + var newSession = session + .CompleteMessages() + .SetSessionState(newSessionState); + + if (scheduledMessages?.Count > 0) + { + newSession = newSession.AppendScheduledMessagesBatch(scheduledMessages); + } + await this.orchestrations.SetAsync(transaction, session.SessionId, newSession); } public async Task AppendMessageAsync(ITransaction transaction, string sessionId, TaskMessage newMessage) { - var newSession = new PersistentSession(sessionId, new OrchestrationRuntimeState(), - ImmutableList.Empty.Add(new LockableTaskMessage() {TaskMessage = newMessage})); + Func newSessionFactory = (sId) => new PersistentSession(sId, new OrchestrationRuntimeState(), + ImmutableList.Empty.Add(new LockableTaskMessage() {TaskMessage = newMessage}), null); await this.orchestrations.AddOrUpdateAsync(transaction, sessionId, - addValue: newSession, + addValueFactory: newSessionFactory, updateValueFactory: (ses, oldValue) => oldValue.AppendMessage(newMessage)); } } From 27abc41d2a238c86e447b0e886885e4c124e7b07 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 23 Aug 2016 14:50:09 -0700 Subject: [PATCH 019/210] Changes that I think will enable sub orchestration and task continuations, need to test the changes though. --- .../FabricOrchestrationService.cs | 26 +++++++++++-------- .../PersistentSession.cs | 2 ++ .../SessionsProvider.cs | 6 ++--- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 014758f1b..9a1b8d3f7 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -161,22 +161,26 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( { Contract.Assert(this.currentSession != null && string.Equals(currentSession.SessionId, workItem.InstanceId), "Unexpected thing happened, complete should be called with the same session as locked"); - if (orchestratorMessages != null && orchestratorMessages.Count > 0) - { - throw new ArgumentException("Sub orchestrations are not supported yet"); - } - - if (continuedAsNewMessage != null) - { - throw new ArgumentException("Continued as new is not supported yet"); - } - using (var txn = this.stateManager.CreateTransaction()) { await this.activitiesProvider.AppendBatch(txn, outboundMessages); await this.orchestrationProvider.CompleteAndUpdateSession(txn, this.currentSession, newOrchestrationRuntimeState, timerMessages); + if (orchestratorMessages?.Count > 0) + { + foreach (var subOrchestrationMessage in orchestratorMessages) + { + //Todo: should we do something like AppendBatch to reduce the number of calls to persistent log? + await this.orchestrationProvider.AppendMessageAsync(txn, subOrchestrationMessage); + } + } + + if (continuedAsNewMessage != null) + { + await this.orchestrationProvider.AppendMessageAsync(txn, continuedAsNewMessage); + } + // Todo: This is not yet part of the transaction if (this.instanceStore != null) { @@ -236,7 +240,7 @@ public async Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workIte { await this.activitiesProvider.CompleteWorkItem(txn, workItem.TaskMessage); var sessionId = workItem.TaskMessage.OrchestrationInstance.InstanceId; - await this.orchestrationProvider.AppendMessageAsync(txn, sessionId, responseMessage); + await this.orchestrationProvider.AppendMessageAsync(txn, responseMessage); await txn.CommitAsync(); this.currentActivity = null; } diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index 0ce6d20b8..33b28d55c 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -25,6 +25,8 @@ namespace DurableTask.ServiceFabric using System.Collections.Immutable; using System.Linq; + // Todo: Write a builder class for this immutable instead of creating intermediate objects for each operation for ex like in + // SessionsProvider.CompleteAndUpdateSession [DataContract] public sealed class PersistentSession { diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index f4ce07fdb..af9787e2e 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -64,7 +64,7 @@ public Task StartAsync() PersistentSession newValue; if (entry.Value.CheckScheduledMessages(out newValue)) { - await this.orchestrations.SetAsync(txn, entry.Key, newValue); //Is this valid code? Can enumeration update the value? + await this.orchestrations.SetAsync(txn, entry.Key, newValue); } } } @@ -134,12 +134,12 @@ public async Task CompleteAndUpdateSession(ITransaction transaction, await this.orchestrations.SetAsync(transaction, session.SessionId, newSession); } - public async Task AppendMessageAsync(ITransaction transaction, string sessionId, TaskMessage newMessage) + public async Task AppendMessageAsync(ITransaction transaction, TaskMessage newMessage) { Func newSessionFactory = (sId) => new PersistentSession(sId, new OrchestrationRuntimeState(), ImmutableList.Empty.Add(new LockableTaskMessage() {TaskMessage = newMessage}), null); - await this.orchestrations.AddOrUpdateAsync(transaction, sessionId, + await this.orchestrations.AddOrUpdateAsync(transaction, newMessage.OrchestrationInstance.InstanceId, addValueFactory: newSessionFactory, updateValueFactory: (ses, oldValue) => oldValue.AppendMessage(newMessage)); } From c3460b2f1b8b4a095c276db7b16f245f1cc5dff0 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 23 Aug 2016 14:51:52 -0700 Subject: [PATCH 020/210] Cleaning up unused code. --- .../DurableTask.ServiceFabric.csproj | 1 - .../FabricStatefulService.cs | 36 ------------------- 2 files changed, 37 deletions(-) delete mode 100644 src/DurableTask.ServiceFabric/FabricStatefulService.cs diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 42a7e2e87..ece49719a 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -76,7 +76,6 @@ - diff --git a/src/DurableTask.ServiceFabric/FabricStatefulService.cs b/src/DurableTask.ServiceFabric/FabricStatefulService.cs deleted file mode 100644 index a24b7e5bf..000000000 --- a/src/DurableTask.ServiceFabric/FabricStatefulService.cs +++ /dev/null @@ -1,36 +0,0 @@ -// ---------------------------------------------------------------------------------- -// Copyright Microsoft Corporation -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ---------------------------------------------------------------------------------- - -namespace DurableTask.ServiceFabric -{ - using System.Collections.Generic; - using System.Fabric; - using System.Threading; - using System.Threading.Tasks; - using Microsoft.ServiceFabric.Data; - using Microsoft.ServiceFabric.Services.Communication.Runtime; - using Microsoft.ServiceFabric.Services.Runtime; - - class FabricStatefulService : StatefulService - { - public FabricStatefulService(StatefulServiceContext serviceContext) - : base(serviceContext) - { - } - - public FabricStatefulService(StatefulServiceContext serviceContext, IReliableStateManagerReplica reliableStateManagerReplica) - : base(serviceContext, reliableStateManagerReplica) - { - } - } -} From a802a56162019d01eb5e3eb6cc6d27cf6222f1d1 Mon Sep 17 00:00:00 2001 From: pradeek Date: Thu, 25 Aug 2016 10:55:48 -0700 Subject: [PATCH 021/210] MSTest based functional tests for service fabric provider. (User SF remoting as communication mechanism for tests) However deploying the local cluster is still a manul pre-req step for tests to run (noted as a todo). Also, at this point, the next step would be to put all existing functional tests for service bus provider into a separate dll and reuse them to test the service fabric provider to understand the gaps. --- .../AssemblySetup.cs | 59 ++++++++++ .../DeploymentUtil/ApplicationInfoReader.cs | 108 ++++++++++++++++++ .../DeploymentUtil/DeploymentHelper.cs | 106 +++++++++++++++++ .../DurableTask.ServiceFabric.Test.csproj | 47 ++++++++ .../FunctionalTests.cs | 46 ++++++++ .../packages.config | 6 + .../TestStatefulService/IRemoteClient.cs | 25 ++++ .../SimpleOrchestrationWithTasks.cs | 2 +- .../SimpleOrchestrationWithTimer.cs | 2 +- .../TestStatefulService.cs | 32 +++++- .../TestStatefulService.csproj | 5 +- 11 files changed, 432 insertions(+), 6 deletions(-) create mode 100644 Test/DurableTask.ServiceFabric.Test/AssemblySetup.cs create mode 100644 Test/DurableTask.ServiceFabric.Test/DeploymentUtil/ApplicationInfoReader.cs create mode 100644 Test/DurableTask.ServiceFabric.Test/DeploymentUtil/DeploymentHelper.cs create mode 100644 Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs create mode 100644 Test/DurableTask.ServiceFabric.Test/packages.config create mode 100644 Test/TestFabricApplication/TestStatefulService/IRemoteClient.cs diff --git a/Test/DurableTask.ServiceFabric.Test/AssemblySetup.cs b/Test/DurableTask.ServiceFabric.Test/AssemblySetup.cs new file mode 100644 index 000000000..e9ee0c813 --- /dev/null +++ b/Test/DurableTask.ServiceFabric.Test/AssemblySetup.cs @@ -0,0 +1,59 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.IO; +using DurableTask.ServiceFabric.Test.DeploymentUtil; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DurableTask.ServiceFabric.Test +{ + [TestClass] + public class AssemblySetup + { + [AssemblyInitialize] + public static void AssemblyInitialize(TestContext testContext) + { + //Todo: This will fail if local cluster is not setup, currently the test code does not automatically + //start a local cluster and that's a manual pre-req step. + DeploymentHelper.CleanAsync().Wait(); + DeploymentHelper.DeployAsync(TestApplicationRootPath).Wait(); + } + + [AssemblyCleanup] + public static void AssemblyCleanup() + { + DeploymentHelper.CleanAsync().Wait(); + } + + static string TestApplicationRootPath + { + get + { + var applicationPath = Path.Combine(Environment.GetEnvironmentVariable("SourceRoot") ?? string.Empty, "Test", "TestFabricApplication", "TestFabricApplication"); + + if (!Directory.Exists(applicationPath)) + { + throw new Exception("Could not find test application path, define SourceRoot environment variable to the source path"); + } + + if (!Directory.Exists(Path.Combine(applicationPath, "pkg", "Debug"))) + { + throw new Exception("Could not find test application package, make sure the test application is built and package generated before running the tests"); + } + + return applicationPath; + } + } + } +} diff --git a/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/ApplicationInfoReader.cs b/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/ApplicationInfoReader.cs new file mode 100644 index 000000000..4ac4b6548 --- /dev/null +++ b/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/ApplicationInfoReader.cs @@ -0,0 +1,108 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Xml; + +namespace DurableTask.ServiceFabric.Test.DeploymentUtil +{ + class ApplicationInfoReader + { + string applicationRootPath; + string applicationPackagePath; + + readonly XmlElement applicationManifestRoot; + readonly XmlNamespaceManager applicationManifestNamespaceManager; + readonly XmlElement serviceManifestRoot; + readonly XmlNamespaceManager serviceManifestNamespaceManager; + + const string ApplicationManifestNodePath = "/sf:ApplicationManifest"; + const string ApplicationNameAttribute = "ApplicationTypeName"; + const string ApplicationVersionAttribute = "ApplicationTypeVersion"; + + const string StatefulServiceNodePath = "/sf:ServiceManifest/sf:ServiceTypes/sf:StatefulServiceType"; + const string StatelessServiceNodePath = "/sf:ServiceManifest/sf:ServiceTypes/sf:StatelessServiceType"; + const string ServiceTypeNameAttribute = "ServiceTypeName"; + + public ApplicationInfoReader(string applicationRootPath) + { + this.applicationRootPath = applicationRootPath; + this.applicationPackagePath = Path.Combine(applicationRootPath, @"pkg\Debug"); + + var applicationManifest = new XmlDocument(); + applicationManifest.Load(Path.Combine(this.applicationPackagePath, "ApplicationManifest.xml")); + this.applicationManifestNamespaceManager = GetXmlNamespaceManager(applicationManifest.NameTable); + this.applicationManifestRoot = applicationManifest.DocumentElement; + + var serviceManifest = new XmlDocument(); + var serviceDirectory = Directory.EnumerateDirectories(this.applicationPackagePath).First(); + serviceManifest.Load(Path.Combine(Path.Combine(this.applicationPackagePath, serviceDirectory), "ServiceManifest.xml")); + this.serviceManifestNamespaceManager = GetXmlNamespaceManager(serviceManifest.NameTable); + this.serviceManifestRoot = serviceManifest.DocumentElement; + } + + public string GetApplicationName() + { + return GetSingleNodeAttributeValue(applicationManifestRoot, applicationManifestNamespaceManager, ApplicationManifestNodePath, ApplicationNameAttribute); + } + + public string GetApplicationVersion() + { + return GetSingleNodeAttributeValue(applicationManifestRoot, applicationManifestNamespaceManager, ApplicationManifestNodePath, ApplicationVersionAttribute); + } + + public string GetServiceName() + { + return GetSingleNodeAttributeValue(serviceManifestRoot, serviceManifestNamespaceManager, StatefulServiceNodePath, ServiceTypeNameAttribute) ?? + GetSingleNodeAttributeValue(serviceManifestRoot, serviceManifestNamespaceManager, StatelessServiceNodePath, ServiceTypeNameAttribute); + } + + public NameValueCollection GetApplicationParameters() + { + var applicationParametersPath = Path.Combine(applicationRootPath, @"ApplicationParameters\Local.xml"); + + var applicationParameters = new XmlDocument(); + applicationParameters.Load(applicationParametersPath); + + var parametersPath = "/sf:Application/sf:Parameters/sf:Parameter"; + var parameters = new NameValueCollection(); + + foreach (var parameterNode in applicationParameters.DocumentElement.SelectNodes(parametersPath, GetXmlNamespaceManager(applicationParameters.NameTable)).OfType()) + { + parameters.Add(parameterNode.Attributes["Name"].Value, parameterNode.Attributes["Value"].Value); + } + + return parameters; + } + + public string ApplicationPackagePath + { + get { return this.applicationPackagePath; } + } + + string GetSingleNodeAttributeValue(XmlElement root, XmlNamespaceManager namespaceManager, string queryPath, string attributeName) + { + var node = root.SelectSingleNode(queryPath, namespaceManager); + return node?.Attributes?[attributeName].Value; + } + + XmlNamespaceManager GetXmlNamespaceManager(XmlNameTable nameTable) + { + var result = new XmlNamespaceManager(nameTable); + result.AddNamespace("sf", "http://schemas.microsoft.com/2011/01/fabric"); + return result; + } + } +} diff --git a/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/DeploymentHelper.cs b/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/DeploymentHelper.cs new file mode 100644 index 000000000..bdb808b09 --- /dev/null +++ b/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/DeploymentHelper.cs @@ -0,0 +1,106 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Fabric; +using System.Fabric.Description; +using System.Fabric.Health; +using System.Fabric.Query; +using System.Linq; +using System.Threading.Tasks; +using System.Xml; + +namespace DurableTask.ServiceFabric.Test.DeploymentUtil +{ + static class DeploymentHelper + { + static readonly FabricClient client = new FabricClient(); + + public static async Task DeployAsync(string applicationRootPath) + { + var appInfoReader = new ApplicationInfoReader(applicationRootPath); + var serviceName = new Uri($"fabric:/{appInfoReader.GetApplicationName()}/{appInfoReader.GetServiceName()}"); + var applicationDescription = + new ApplicationDescription( + new Uri($"fabric:/{appInfoReader.GetApplicationName()}"), + appInfoReader.GetApplicationName(), + appInfoReader.GetApplicationVersion(), + appInfoReader.GetApplicationParameters()); + + await DeployAsync(appInfoReader.ApplicationPackagePath, applicationDescription); + await WaitForHealthStatusAsync(applicationDescription, serviceName); + } + + public static async Task CleanAsync() + { + var applications = await client.QueryManager.GetApplicationListAsync(); + foreach (var application in applications) + { + await client.ApplicationManager.DeleteApplicationAsync(application.ApplicationName); + + foreach (var node in await client.QueryManager.GetNodeListAsync()) + { + var replicas = (await client.QueryManager.GetDeployedReplicaListAsync(node.NodeName, application.ApplicationName)).OfType(); + foreach (var replica in replicas) + { + await client.ServiceManager.RemoveReplicaAsync(node.NodeName, replica.Partitionid, replica.ReplicaId); + } + } + } + + var applicationTypeList = await client.QueryManager.GetApplicationTypeListAsync(); + foreach (var applicationType in applicationTypeList) + { + await client.ApplicationManager.UnprovisionApplicationAsync(applicationType.ApplicationTypeName, applicationType.ApplicationTypeVersion); + } + } + + static async Task DeployAsync(string applicationPackagePath, ApplicationDescription applicationDescription) + { + var clusterManifest = new XmlDocument(); + var clusterManifestXml = await client.ClusterManager.GetClusterManifestAsync(); + clusterManifest.LoadXml(clusterManifestXml); + var namespaceManager = new XmlNamespaceManager(clusterManifest.NameTable); + namespaceManager.AddNamespace("sf", "http://schemas.microsoft.com/2011/01/fabric"); + var imageStoreConnectionStringPath = "/sf:ClusterManifest/sf:FabricSettings/sf:Section[@Name='Management']/sf:Parameter[@Name='ImageStoreConnectionString']"; + var imageStoreConnectionStringNode = clusterManifest.DocumentElement.SelectSingleNode(imageStoreConnectionStringPath, namespaceManager); + var imageStoreConnectionString = imageStoreConnectionStringNode.Attributes["Value"].Value; + + var path = Guid.NewGuid().ToString(); + client.ApplicationManager.CopyApplicationPackage(imageStoreConnectionString, applicationPackagePath, path); + + await client.ApplicationManager.ProvisionApplicationAsync(path); + + client.ApplicationManager.RemoveApplicationPackage(imageStoreConnectionString, path); + + await client.ApplicationManager.CreateApplicationAsync(applicationDescription); + } + + static async Task WaitForHealthStatusAsync(ApplicationDescription applicationDescription, Uri serviceName) + { + while (true) + { + await Task.Delay(TimeSpan.FromSeconds(2)); + var states = (await client.HealthManager.GetApplicationHealthAsync(applicationDescription.ApplicationName)).ServiceHealthStates; + if (states.Any() && states.All(s => s.AggregatedHealthState == HealthState.Ok)) + { + return; + } + if (states.Any() && states.Any(s => s.AggregatedHealthState == HealthState.Error || s.AggregatedHealthState == HealthState.Invalid)) + { + throw new Exception($"Deployment of {serviceName} failed"); + } + } + } + } +} diff --git a/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj b/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj index 8afb490a0..7a03f76ea 100644 --- a/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj +++ b/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj @@ -20,6 +20,7 @@ DEBUG;TRACE prompt 4 + x64 pdbonly @@ -30,9 +31,39 @@ 4 + + ..\..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll + True + + + False + ..\..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll + True + + + ..\..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.dll + True + + + ..\..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll + True + + + ..\..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\Microsoft.ServiceFabric.Services.dll + True + + + ..\..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\ServiceFabricServiceModel.dll + True + + + ..\..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\System.Fabric.dll + True + + @@ -41,16 +72,32 @@ + + + + + + {6f5d2ead-726d-4fe5-a575-aeb96d1cce37} + DurableTask.Framework + {5c617b24-4902-4992-8f71-ab14f00b74a8} DurableTask.ServiceFabric + + {95d6c9c7-f7a0-4125-840d-1854bec24978} + TestStatefulService + + + + + Sleeping for '{4}'", instance.InstanceId, instance.ExecutionId, input.TaskId, c, minutesToSleep)); - await Task.Delay(TimeSpan.FromMinutes(minutesToSleep)); + await Task.Delay(TimeSpan.FromSeconds(minutesToSleep)); return c; } diff --git a/Test/TestFabricApplication/TestStatefulService/IRemoteClient.cs b/Test/TestFabricApplication/TestStatefulService/IRemoteClient.cs index 0119d726a..0954aadb2 100644 --- a/Test/TestFabricApplication/TestStatefulService/IRemoteClient.cs +++ b/Test/TestFabricApplication/TestStatefulService/IRemoteClient.cs @@ -14,6 +14,7 @@ using System; using System.Threading.Tasks; using DurableTask; +using DurableTask.Test.Orchestrations.Stress; using Microsoft.ServiceFabric.Services.Remoting; namespace TestStatefulService @@ -21,5 +22,7 @@ namespace TestStatefulService public interface IRemoteClient : IService { Task RunOrchestrationAsync(string orchestrationTypeName, object input, TimeSpan waitTimeout); + + Task RunDriverOrchestrationAsync(DriverOrchestrationData input, TimeSpan waitTimeout); } } diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index e9b7d7c68..10fe6a2c6 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -25,6 +25,7 @@ using TestStatefulService.DebugHelper; using TestStatefulService.TestOrchestrations; using Microsoft.ServiceFabric.Services.Remoting.Runtime; +using DurableTask.Test.Orchestrations.Stress; namespace TestStatefulService { @@ -70,9 +71,12 @@ protected override IEnumerable CreateServiceReplicaListe /// Canceled when Service Fabric needs to shut down this service replica. protected override async Task RunAsync(CancellationToken cancellationToken) { + var testTask = new TestTask(); + await this.worker .AddTaskOrchestrations(KnownOrchestrationTypeNames.Values.ToArray()) - .AddTaskActivities(typeof(GetUserTask), typeof(GreetUserTask), typeof(GenerationBasicTask)) + .AddTaskActivities(KnownActivities) + .AddTaskActivities(testTask) .StartAsync(); //await this.testExecutor.StartAsync(); @@ -94,6 +98,11 @@ public async Task RunOrchestrationAsync(string orchestration return await client.WaitForOrchestrationAsync(instance, waitTimeout); } + public async Task RunDriverOrchestrationAsync(DriverOrchestrationData input, TimeSpan waitTimeout) + { + return await this.RunOrchestrationAsync(typeof(DriverOrchestration).Name, input, waitTimeout); + } + Type GetOrchestrationType(string typeName) { if (!KnownOrchestrationTypeNames.ContainsKey(typeName)) @@ -104,12 +113,21 @@ Type GetOrchestrationType(string typeName) return KnownOrchestrationTypeNames.First(kvp => string.Equals(typeName, kvp.Key)).Value; } - private static Dictionary KnownOrchestrationTypeNames = new Dictionary + static Dictionary KnownOrchestrationTypeNames = new Dictionary { { typeof(SimpleOrchestrationWithTasks).Name, typeof(SimpleOrchestrationWithTasks) }, { typeof(SimpleOrchestrationWithTimer).Name, typeof(SimpleOrchestrationWithTimer) }, { typeof(GenerationBasicOrchestration).Name, typeof(GenerationBasicOrchestration) }, { typeof(SimpleOrchestrationWithSubOrchestration).Name, typeof(SimpleOrchestrationWithSubOrchestration) }, + { typeof(DriverOrchestration).Name, typeof(DriverOrchestration) }, + { typeof(TestOrchestration).Name, typeof(TestOrchestration) }, + }; + + static Type[] KnownActivities = + { + typeof(GetUserTask), + typeof(GreetUserTask), + typeof(GenerationBasicTask), }; } } diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj index b2df94292..7cf2935fc 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj @@ -140,6 +140,10 @@ {5c617b24-4902-4992-8f71-ab14f00b74a8} DurableTask.ServiceFabric + + {2bc2a5ad-4200-41b9-a034-332bb1d7187b} + DurableTask.Test.Orchestrations + {ea90334d-3194-4266-81eb-eeca9c760315} TestApplication.Common From bd3c0baab9f711dc8874bbfa4d4159c98bfdd2c4 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 031/210] Minor change to stress test to also emit the orchestration time in addition to stop watch time. --- Test/DurableTask.ServiceFabric.Test/StressTests.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.Test/StressTests.cs b/Test/DurableTask.ServiceFabric.Test/StressTests.cs index 6ca8cbaa2..90bef2684 100644 --- a/Test/DurableTask.ServiceFabric.Test/StressTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/StressTests.cs @@ -52,8 +52,11 @@ public async Task ExecuteStressTest() Console.WriteLine($"Orchestration Status: {state.OrchestrationStatus}"); TimeSpan totalTime = stopWatch.Elapsed; - string elapsedTime = $"{totalTime.Hours:00}:{totalTime.Minutes:00}:{totalTime.Seconds:00}.{totalTime.Milliseconds / 10:00}"; - Console.WriteLine($"Total Time: {elapsedTime}"); + TimeSpan orchestrationTime = state.CompletedTime - state.CreatedTime; + + Func elapsedTimeFormatter = timeSpan => $"{timeSpan.Hours:00}:{timeSpan.Minutes:00}:{timeSpan.Seconds:00}.{timeSpan.Milliseconds / 10:00}"; + Console.WriteLine($"Total Meastured Time: {elapsedTimeFormatter(totalTime)}"); + Console.WriteLine($"Top level Orchestration Time: {elapsedTimeFormatter(orchestrationTime)}"); } } } From d730c829c5310ca0c50d49897c8f8381caed445d Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 032/210] Removing the use of SetAsync and using AddOrUpdateAsync instead. This will ensure the changes are not overwritten between transactions. --- .../FabricOrchestrationService.cs | 2 +- .../FabricOrchestrationServiceClient.cs | 2 +- .../PersistentSession.cs | 24 ++++++++--- .../SessionsProvider.cs | 43 ++++++++++++------- 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index e4510f530..a457eaa9b 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -170,7 +170,7 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( { await this.activitiesProvider.AppendBatch(txn, outboundMessages); - await this.orchestrationProvider.CompleteAndUpdateSession(txn, this.currentSession, newOrchestrationRuntimeState, timerMessages); + await this.orchestrationProvider.CompleteAndUpdateSession(txn, this.currentSession.SessionId, newOrchestrationRuntimeState, timerMessages); if (orchestratorMessages?.Count > 0) { diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index e0224bd4d..4bd9c4604 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -55,7 +55,7 @@ public async Task SendTaskOrchestrationMessageAsync(TaskMessage message) var sessionId = message.OrchestrationInstance.InstanceId; //Todo: This is the same code as SessionsProvider.AppendMessages, can perhaps reuse somehow? - Func newSessionFactory = (sid) => new PersistentSession(sessionId, new OrchestrationRuntimeState(), new LockableTaskMessage(message)); + Func newSessionFactory = (sid) => new PersistentSession(sessionId, message); await orchestrations.AddOrUpdateAsync(txn, sessionId, addValueFactory: newSessionFactory, diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index c3523fff0..854b78133 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -27,14 +27,24 @@ namespace DurableTask.ServiceFabric using System.Linq; // Todo: Write a builder class for this immutable instead of creating intermediate objects for each operation for ex like in - // SessionsProvider.CompleteAndUpdateSession + // SessionsProvider.CompleteAndUpdateSession. [DataContract] public sealed class PersistentSession { static readonly IEnumerable NoMessages = ImmutableList.Empty; static readonly DataConverter DatConverter = new JsonDataConverter(); - public PersistentSession(string sessionId, OrchestrationRuntimeState sessionState, LockableTaskMessage message) + public PersistentSession(string sessionId) + : this(sessionId, null, null, null) + { + } + + public PersistentSession(string sessionId, TaskMessage newMessage) + : this(sessionId, new LockableTaskMessage(newMessage), null) + { + } + + public PersistentSession(string sessionId, LockableTaskMessage message, OrchestrationRuntimeState sessionState) : this(sessionId, sessionState, new LockableTaskMessage[] {message}, null) { } @@ -101,12 +111,11 @@ public PersistentSession AppendScheduledMessagesBatch(IEnumerable n } // Todo: Can optimize in a few other ways, for now, something that works - public bool CheckScheduledMessages(out PersistentSession newValue) + public PersistentSession FireScheduledMessages() { - newValue = this; if (!this.ScheduledMessages.Any()) { - return false; + return this; } bool changed = false; @@ -137,9 +146,10 @@ public bool CheckScheduledMessages(out PersistentSession newValue) if (changed) { - newValue = new PersistentSession(this.SessionId, this.SessionState, newMessages, remainingScheduledMessages); + return new PersistentSession(this.SessionId, this.SessionState, newMessages, remainingScheduledMessages); } - return changed; + + return this; } public List ReceiveMessages() diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 8a9e05320..350083829 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -29,6 +29,8 @@ class SessionsProvider IReliableDictionary orchestrations; CancellationTokenSource cancellationTokenSource; + readonly Func NewSessionFactory = (sId) => new PersistentSession(sId); + public SessionsProvider(IReliableStateManager stateManager, IReliableDictionary orchestrations) { if (stateManager == null) @@ -53,6 +55,8 @@ public Task StartAsync() while (!this.cancellationTokenSource.IsCancellationRequested) { await Task.Delay(TimeSpan.FromMilliseconds(100)); + + var scheduledMessageSessions = new List(); using (var txn = this.stateManager.CreateTransaction()) { var enumerable = await this.orchestrations.CreateEnumerableAsync(txn, EnumerationMode.Unordered); @@ -61,16 +65,23 @@ public Task StartAsync() while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) { var entry = enumerator.Current; - PersistentSession newValue; - if (entry.Value.CheckScheduledMessages(out newValue)) + if (entry.Value.ScheduledMessages.Any()) { - //Todo: SetAsync is probably bad because it may be overwriting some changes? Unless we make it thread-safe? - await this.orchestrations.SetAsync(txn, entry.Key, newValue); + scheduledMessageSessions.Add(entry.Key); } } } await txn.CommitAsync(); } + + foreach (var sessionId in scheduledMessageSessions) + { + using (var txn = this.stateManager.CreateTransaction()) + { + await this.orchestrations.AddOrUpdateAsync(txn, sessionId, NewSessionFactory, (sId, oldValue) => oldValue.FireScheduledMessages()); + await txn.CommitAsync(); + } + } } }); @@ -119,26 +130,28 @@ public List GetSessionMessages(PersistentSession session) } public async Task CompleteAndUpdateSession(ITransaction transaction, - PersistentSession session, + string sessionId, OrchestrationRuntimeState newSessionState, IList scheduledMessages) { - var newSession = session - .CompleteMessages() - .SetSessionState(newSessionState); - - if (scheduledMessages?.Count > 0) + await this.orchestrations.AddOrUpdateAsync(transaction, sessionId, NewSessionFactory, (sId, oldValue) => { - newSession = newSession.AppendScheduledMessagesBatch(scheduledMessages); - } + var newSession = oldValue + .CompleteMessages() + .SetSessionState(newSessionState); + + if (scheduledMessages?.Count > 0) + { + newSession = newSession.AppendScheduledMessagesBatch(scheduledMessages); + } - await this.orchestrations.SetAsync(transaction, session.SessionId, newSession); + return newSession; + }); } public async Task AppendMessageAsync(ITransaction transaction, TaskMessage newMessage) { - Func newSessionFactory = (sId) => new PersistentSession(sId, new OrchestrationRuntimeState(), - ImmutableList.Empty.Add(new LockableTaskMessage(newMessage)), null); + Func newSessionFactory = (sId) => new PersistentSession(sId, newMessage); await this.orchestrations.AddOrUpdateAsync(transaction, newMessage.OrchestrationInstance.InstanceId, addValueFactory: newSessionFactory, From 365ef4d8b3504e6f089a8814bd916cce78abe907 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 033/210] Minor change to timer test to log the orchestration time and waiter time for comparison. --- Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs index 75bf601e1..20e0e9c2d 100644 --- a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs @@ -44,11 +44,14 @@ public async Task Orchestration_With_ScheduledTasks_Finishes() [TestMethod] public async Task Orchestration_With_Timer_Finishes_After_The_Wait_Time() { - var result = await this.serviceClient.RunOrchestrationAsync(typeof(SimpleOrchestrationWithTimer).Name, 37, TimeSpan.FromMinutes(5)); + var waitTime = 37; + var result = await this.serviceClient.RunOrchestrationAsync(typeof(SimpleOrchestrationWithTimer).Name, waitTime, TimeSpan.FromMinutes(5)); Assert.AreEqual(OrchestrationStatus.Completed, result.OrchestrationStatus); Assert.AreEqual("\"Hello Gabbar\"", result.Output); - Assert.IsTrue((result.CompletedTime - result.CreatedTime) > TimeSpan.FromSeconds(37)); + var orchestrationTime = result.CompletedTime - result.CreatedTime; + Assert.IsTrue(orchestrationTime > TimeSpan.FromSeconds(waitTime)); + Console.WriteLine($"Time for Orchestration : {orchestrationTime}, Timer Wait time : {waitTime}"); } [TestMethod] From add5984db2d16aad4331acfb19acab893ea47b0e Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 034/210] nit changes. --- src/DurableTask.ServiceFabric/ActivitiesProvider.cs | 2 +- src/DurableTask.ServiceFabric/PersistentSession.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs index 99cea456c..3b74eb1ef 100644 --- a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs +++ b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs @@ -54,7 +54,7 @@ public async Task GetNextWorkItem(TimeSpan receiveTimeout, Cancella { return activityValue.Value; } - //Todo: Need commit here? + //Todo: Need commit here? And in all other places where we create a transaction but do read-only operations? } await Task.Delay(100, cancellationToken); } diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index 854b78133..02aeb5f1d 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -45,7 +45,7 @@ public PersistentSession(string sessionId, TaskMessage newMessage) } public PersistentSession(string sessionId, LockableTaskMessage message, OrchestrationRuntimeState sessionState) - : this(sessionId, sessionState, new LockableTaskMessage[] {message}, null) + : this(sessionId, sessionState, new [] {message}, null) { } From 3b710bccf256e16aef17fe5755ab85a7c995bb8a Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 035/210] more comments / todo. --- src/DurableTask.ServiceFabric/PersistentSession.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index 02aeb5f1d..de05b2879 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -151,7 +151,15 @@ public PersistentSession FireScheduledMessages() return this; } - + + //Todo: Though this is functionally ok with the current design, it has some issues. + // This sequence of events is a possibility: + // - AcceptSession fetches a session (object1) with active messages and returns it + // - Meanwhile a work item finishes and appends a new message and saves it so the orchestration dictionary has a different session instance (object2). + // - Now ReceiveMessages is called on (object1) and all it's messages are marked as received. + // - However Next Complete call will see (object2) and there's nothing really marked as received so it won't delete the processed session messages. + // Functional impact of above such scenario is duplicate processing of session messages which is extra processing but correct nevertheless since + // orchestration processing is idempotent. However performance is definetely negatively impacted. public List ReceiveMessages() { // Todo: Need to be thread-safe? From 9ef2e96216a7f18db04fdd6b853d5a64cd3b4455 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 036/210] There is no need to call CommitAsync for read-only transactions because the end of using clause will cause a dispose on transaction which will release any locks. --- src/DurableTask.ServiceFabric/ActivitiesProvider.cs | 1 - .../FabricOrchestrationInstanceStore.cs | 1 - src/DurableTask.ServiceFabric/SessionsProvider.cs | 5 ++--- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs index 3b74eb1ef..b89b5e8ad 100644 --- a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs +++ b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs @@ -54,7 +54,6 @@ public async Task GetNextWorkItem(TimeSpan receiveTimeout, Cancella { return activityValue.Value; } - //Todo: Need commit here? And in all other places where we create a transaction but do read-only operations? } await Task.Delay(100, cancellationToken); } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs index ddd9a91de..6e83158af 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs @@ -94,7 +94,6 @@ public async Task GetOrchestrationStateAsync(s State = state.Value, }; } - //Todo: Do I need commit transaction here? } return null; diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 350083829..c5416c7cb 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -54,8 +54,6 @@ public Task StartAsync() { while (!this.cancellationTokenSource.IsCancellationRequested) { - await Task.Delay(TimeSpan.FromMilliseconds(100)); - var scheduledMessageSessions = new List(); using (var txn = this.stateManager.CreateTransaction()) { @@ -71,7 +69,6 @@ public Task StartAsync() } } } - await txn.CommitAsync(); } foreach (var sessionId in scheduledMessageSessions) @@ -82,6 +79,8 @@ public Task StartAsync() await txn.CommitAsync(); } } + + await Task.Delay(TimeSpan.FromMilliseconds(100)); } }); From 750977ce734e18878da31e3d7d22e1233e4ed34e Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 037/210] An attempt to use code generation tool for the immutable class. However test are not working, so there's some regression. Need to debug. --- .../DurableTask.ServiceFabric.Test/app.config | 4 + .../DurableTask.ServiceFabric.csproj | 29 +++++ .../FabricOrchestrationService.cs | 6 +- .../FabricOrchestrationServiceClient.cs | 6 +- .../PersistentSession.api.cs | 102 ++++++++++++++++++ .../PersistentSession.cs | 13 +-- .../PersistentSession2.cs | 49 +++++++++ .../SessionsProvider.cs | 46 ++++---- src/DurableTask.ServiceFabric/app.config | 2 +- src/DurableTask.ServiceFabric/packages.config | 10 ++ 10 files changed, 228 insertions(+), 39 deletions(-) create mode 100644 src/DurableTask.ServiceFabric/PersistentSession.api.cs create mode 100644 src/DurableTask.ServiceFabric/PersistentSession2.cs diff --git a/Test/DurableTask.ServiceFabric.Test/app.config b/Test/DurableTask.ServiceFabric.Test/app.config index 195db1f42..134e4b51a 100644 --- a/Test/DurableTask.ServiceFabric.Test/app.config +++ b/Test/DurableTask.ServiceFabric.Test/app.config @@ -6,6 +6,10 @@ + + + + \ No newline at end of file diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index ece49719a..0fe483102 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -11,6 +11,8 @@ DurableTask.ServiceFabric v4.5.2 512 + + true @@ -30,6 +32,14 @@ 4 + + ..\..\packages\ImmutableObjectGraph.1.1.98-beta\lib\dotnet\ImmutableObjectGraph.dll + True + + + ..\..\packages\ImmutableObjectGraph.Generation.1.1.98-beta\lib\dotnet\ImmutableObjectGraph.Generation.Attributes.dll + True + ..\..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll True @@ -69,6 +79,10 @@ + + ..\..\packages\Validation.2.2.8\lib\dotnet\Validation.dll + True + @@ -76,7 +90,13 @@ + + PersistentSession2.cs + + + MSBuild:GenerateCodeFromAttributes + @@ -93,6 +113,15 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs b/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs new file mode 100644 index 000000000..bea230892 --- /dev/null +++ b/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs @@ -0,0 +1,116 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using DurableTask.Test.Orchestrations.Stress; +using Microsoft.ServiceFabric.Services.Client; +using Microsoft.ServiceFabric.Services.Remoting.Client; +using TestApplication.Common; + +namespace DurableTask.ServiceFabric.Stress.Tests +{ + class Program + { + static ConcurrentBag instances = new ConcurrentBag(); + static IRemoteClient serviceClient = ServiceProxy.Create(new Uri("fabric:/TestFabricApplication/TestStatefulService"), new ServicePartitionKey(1)); + static Dictionary outcomeFrequencies = new Dictionary(); + + static void Main(string[] args) + { + CancellationTokenSource cts1 = new CancellationTokenSource(); + CancellationTokenSource cts2 = new CancellationTokenSource(); + + var programTask = RunOrchestrations(cts1.Token); + var statusTask = PollState(cts2.Token); + + Console.WriteLine("Press any key to stop running orchestrations and print results"); + Console.ReadKey(); + + cts1.Cancel(); + programTask.Wait(); + + cts2.Cancel(); + statusTask.Wait(); + } + + static async Task PollState(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + await PrintStatusAggregation(); + await Task.Delay(TimeSpan.FromSeconds(10)); + } + await PrintStatusAggregation(); + } + + static async Task PrintStatusAggregation() + { + Console.WriteLine($"Numer of instances so far : {instances.Count}"); + foreach (var instance in instances) + { + var state = await serviceClient.GetOrchestrationState(instance); + var key = state != null ? state.OrchestrationStatus.ToString() : "NullState"; + + if (!outcomeFrequencies.ContainsKey(key)) + { + outcomeFrequencies.Add(key, 0); + } + + outcomeFrequencies[key]++; + } + + foreach (var kvp in outcomeFrequencies) + { + Console.WriteLine($"{kvp.Key} : {kvp.Value}"); + } + + outcomeFrequencies.Clear(); + } + + static async Task RunOrchestrations(CancellationToken cancellationToken) + { + int totalRequests = 0; + List tasks = new List(); + Console.WriteLine("Starting orchestrations"); + + while (!cancellationToken.IsCancellationRequested) + { + var newOrchData = new TestOrchestrationData() + { + NumberOfParallelTasks = 15, + NumberOfSerialTasks = 5, + MaxDelayInMinutes = 0 + }; + + totalRequests++; + var instance = await serviceClient.StartTestOrchestrationAsync(newOrchData); + instances.Add(instance); + var waitTask = serviceClient.WaitForOrchestration(instance, TimeSpan.FromMinutes(2)); + + tasks.Add(waitTask); + + await Task.Delay(TimeSpan.FromMilliseconds(100)); + } + + Console.WriteLine($"Total orchestrations : {totalRequests}"); + Console.WriteLine("Waiting for pending orchestrations"); + await Task.WhenAll(tasks); + + Console.WriteLine("Done"); + } + } +} diff --git a/Test/DurableTask.ServiceFabric.Stress.Tests/Properties/AssemblyInfo.cs b/Test/DurableTask.ServiceFabric.Stress.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..5172daa5c --- /dev/null +++ b/Test/DurableTask.ServiceFabric.Stress.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DurableTask.ServiceFabric.Stress.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DurableTask.ServiceFabric.Stress.Tests")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("be4624f3-e565-428f-9eed-e6847530746a")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Test/DurableTask.ServiceFabric.Stress.Tests/packages.config b/Test/DurableTask.ServiceFabric.Stress.Tests/packages.config new file mode 100644 index 000000000..1fb365a00 --- /dev/null +++ b/Test/DurableTask.ServiceFabric.Stress.Tests/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj b/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj index f1e2f961e..1f9e4a2c4 100644 --- a/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj +++ b/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj @@ -9,7 +9,7 @@ Properties DurableTask.ServiceFabric.Test DurableTask.ServiceFabric.Test - v4.5.2 + v4.5.1 512 @@ -92,6 +92,10 @@ {2bc2a5ad-4200-41b9-a034-332bb1d7187b} DurableTask.Test.Orchestrations + + {ea90334d-3194-4266-81eb-eeca9c760315} + TestApplication.Common + {95d6c9c7-f7a0-4125-840d-1854bec24978} TestStatefulService diff --git a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs index 20e0e9c2d..3bfbe7438 100644 --- a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs @@ -16,7 +16,7 @@ using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; using Microsoft.VisualStudio.TestTools.UnitTesting; -using TestStatefulService; +using TestApplication.Common; using TestStatefulService.TestOrchestrations; namespace DurableTask.ServiceFabric.Test diff --git a/Test/DurableTask.ServiceFabric.Test/StressTests.cs b/Test/DurableTask.ServiceFabric.Test/StressTests.cs index 90bef2684..a080a1efd 100644 --- a/Test/DurableTask.ServiceFabric.Test/StressTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/StressTests.cs @@ -11,17 +11,17 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using DurableTask.Test.Orchestrations.Stress; +using Microsoft.ServiceFabric.Services.Client; +using Microsoft.ServiceFabric.Services.Remoting.Client; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TestApplication.Common; + namespace DurableTask.ServiceFabric.Test { - using System; - using System.Diagnostics; - using System.Threading.Tasks; - using DurableTask.Test.Orchestrations.Stress; - using Microsoft.ServiceFabric.Services.Client; - using Microsoft.ServiceFabric.Services.Remoting.Client; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using TestStatefulService; - [TestClass] public class StressTests { diff --git a/Test/TestFabricApplication/TestStatefulService/IRemoteClient.cs b/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs similarity index 78% rename from Test/TestFabricApplication/TestStatefulService/IRemoteClient.cs rename to Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs index 0954aadb2..231c036b0 100644 --- a/Test/TestFabricApplication/TestStatefulService/IRemoteClient.cs +++ b/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs @@ -17,12 +17,18 @@ using DurableTask.Test.Orchestrations.Stress; using Microsoft.ServiceFabric.Services.Remoting; -namespace TestStatefulService +namespace TestApplication.Common { public interface IRemoteClient : IService { Task RunOrchestrationAsync(string orchestrationTypeName, object input, TimeSpan waitTimeout); Task RunDriverOrchestrationAsync(DriverOrchestrationData input, TimeSpan waitTimeout); + + Task StartTestOrchestrationAsync(TestOrchestrationData input); + + Task GetOrchestrationState(OrchestrationInstance instance); + + Task WaitForOrchestration(OrchestrationInstance instance, TimeSpan waitTimeout); } } diff --git a/Test/TestFabricApplication/TestApplication.Common/TestApplication.Common.csproj b/Test/TestFabricApplication/TestApplication.Common/TestApplication.Common.csproj index a34f676ab..ad39069a6 100644 --- a/Test/TestFabricApplication/TestApplication.Common/TestApplication.Common.csproj +++ b/Test/TestFabricApplication/TestApplication.Common/TestApplication.Common.csproj @@ -9,7 +9,7 @@ Properties TestApplication.Common TestApplication.Common - v4.5.2 + v4.5.1 512 @@ -82,12 +82,23 @@ + + + + {6f5d2ead-726d-4fe5-a575-aeb96d1cce37} + DurableTask.Framework + + + {2bc2a5ad-4200-41b9-a034-332bb1d7187b} + DurableTask.Test.Orchestrations + + + \ No newline at end of file diff --git a/Test/DurableTask.ServiceFabric.Test/UnitTests/PersistentSessionTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs similarity index 97% rename from Test/DurableTask.ServiceFabric.Test/UnitTests/PersistentSessionTests.cs rename to Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs index d9102ea8c..c8b8fd834 100644 --- a/Test/DurableTask.ServiceFabric.Test/UnitTests/PersistentSessionTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs @@ -17,7 +17,7 @@ using DurableTask.History; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace DurableTask.ServiceFabric.Test.UnitTests +namespace DurableTask.ServiceFabric.UnitTests { [TestClass] public class PersistentSessionTests diff --git a/Test/DurableTask.ServiceFabric.UnitTests/Properties/AssemblyInfo.cs b/Test/DurableTask.ServiceFabric.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..e73ff9a61 --- /dev/null +++ b/Test/DurableTask.ServiceFabric.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DurableTask.ServiceFabric.UnitTests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DurableTask.ServiceFabric.UnitTests")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("31c9c932-6376-46d4-a68a-a0a7f2726d38")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Test/DurableTask.ServiceFabric.UnitTests/app.config b/Test/DurableTask.ServiceFabric.UnitTests/app.config new file mode 100644 index 000000000..195db1f42 --- /dev/null +++ b/Test/DurableTask.ServiceFabric.UnitTests/app.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Test/DurableTask.ServiceFabric.UnitTests/packages.config b/Test/DurableTask.ServiceFabric.UnitTests/packages.config new file mode 100644 index 000000000..a5a743bc5 --- /dev/null +++ b/Test/DurableTask.ServiceFabric.UnitTests/packages.config @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file From 020cc3c69641c603bee84a3788c4496501e0db5d Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 16 Sep 2016 10:35:46 -0700 Subject: [PATCH 054/210] Expanding the test to cover all fields. (And to measure time) --- .../PersistentSessionTests.cs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs index c8b8fd834..893deea2b 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs @@ -11,7 +11,9 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using System; using System.Collections.Immutable; +using System.Diagnostics; using System.IO; using System.Runtime.Serialization; using DurableTask.History; @@ -32,21 +34,41 @@ public void SerializationTest() new TaskScheduledEvent(-1), new TaskCompletedEvent(-1, -1, "SomeResult"), new ExecutionCompletedEvent(-1, "SomeResult", OrchestrationStatus.Completed) - }; + }.ToImmutableList(); - PersistentSession testSession = PersistentSession.Create(sessionId: "testSession", sessionState: events.ToImmutableList()); + var messages = new ReceivableTaskMessage[] + { + ReceivableTaskMessage.Create(new TaskMessage() {SequenceNumber = 1}), + ReceivableTaskMessage.Create(new TaskMessage() {SequenceNumber = 2}), + }.ToImmutableList(); + + var scheduledMessages = new ReceivableTaskMessage[] + { + ReceivableTaskMessage.Create(new TaskMessage() {SequenceNumber = 3}), + }.ToImmutableList(); + + PersistentSession testSession = PersistentSession.Create("testSession", events, messages, scheduledMessages, isLocked: true); using (var stream = new MemoryStream()) { var serializer = new DataContractSerializer(typeof(PersistentSession)); + Stopwatch timer = Stopwatch.StartNew(); serializer.WriteObject(stream, testSession); + timer.Stop(); + Console.WriteLine($"Time for serialization : {timer.ElapsedMilliseconds} ms"); stream.Position = 0; + timer.Restart(); var deserialized = (PersistentSession)serializer.ReadObject(stream); + timer.Stop(); + Console.WriteLine($"Time for deserialization : {timer.ElapsedMilliseconds} ms"); Assert.IsNotNull(deserialized); Assert.AreEqual("testSession", deserialized.SessionId); + Assert.IsFalse(deserialized.IsLocked); Assert.AreEqual(4, deserialized.SessionState.Count); + Assert.AreEqual(2, deserialized.Messages.Count); + Assert.AreEqual(1, deserialized.ScheduledMessages.Count); } } } From d7c64ef94c32f681281a66b4450ebcc62bc1dae4 Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 16 Sep 2016 10:35:46 -0700 Subject: [PATCH 055/210] Adapting the test a bit to be able to easily increase the size of object being serialized to measure perf. --- .../PersistentSessionTests.cs | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs index 893deea2b..07d825cc5 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs @@ -12,6 +12,7 @@ // ---------------------------------------------------------------------------------- using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.IO; @@ -28,26 +29,31 @@ public class PersistentSessionTests [Ignore] //Todo public void SerializationTest() { - var events = new HistoryEvent[] + int numberOfItemsInCollections = 2; + + var events = new List(); + events.Add(new ExecutionStartedEvent(-1, "TestInput")); + for (int i = 0; i < numberOfItemsInCollections; i++) { - new ExecutionStartedEvent(-1, "TestInput"), - new TaskScheduledEvent(-1), - new TaskCompletedEvent(-1, -1, "SomeResult"), - new ExecutionCompletedEvent(-1, "SomeResult", OrchestrationStatus.Completed) - }.ToImmutableList(); + events.Add(new TaskScheduledEvent(-1)); + events.Add(new TaskCompletedEvent(-1, -1, $"Task {i} Result")); + } + events.Add(new ExecutionCompletedEvent(-1, "FinalResult", OrchestrationStatus.Completed)); - var messages = new ReceivableTaskMessage[] + var messages = new List(); + for (int i = 0; i < numberOfItemsInCollections; i++) { - ReceivableTaskMessage.Create(new TaskMessage() {SequenceNumber = 1}), - ReceivableTaskMessage.Create(new TaskMessage() {SequenceNumber = 2}), - }.ToImmutableList(); + messages.Add(ReceivableTaskMessage.Create(new TaskMessage() { SequenceNumber = i })); + } - var scheduledMessages = new ReceivableTaskMessage[] + var scheduledMessages = new List(); + for (int i = 0; i < numberOfItemsInCollections; i++) { - ReceivableTaskMessage.Create(new TaskMessage() {SequenceNumber = 3}), - }.ToImmutableList(); + scheduledMessages.Add(ReceivableTaskMessage.Create(new TaskMessage() { SequenceNumber = i })); + } - PersistentSession testSession = PersistentSession.Create("testSession", events, messages, scheduledMessages, isLocked: true); + PersistentSession testSession = PersistentSession.Create("testSession", events.ToImmutableList(), + messages.ToImmutableList(), scheduledMessages.ToImmutableList(), isLocked: true); using (var stream = new MemoryStream()) { @@ -66,9 +72,9 @@ public void SerializationTest() Assert.IsNotNull(deserialized); Assert.AreEqual("testSession", deserialized.SessionId); Assert.IsFalse(deserialized.IsLocked); - Assert.AreEqual(4, deserialized.SessionState.Count); - Assert.AreEqual(2, deserialized.Messages.Count); - Assert.AreEqual(1, deserialized.ScheduledMessages.Count); + Assert.AreEqual(numberOfItemsInCollections*2 + 2, deserialized.SessionState.Count); + Assert.AreEqual(numberOfItemsInCollections, deserialized.Messages.Count); + Assert.AreEqual(numberOfItemsInCollections, deserialized.ScheduledMessages.Count); } } } From 3041f8c039903b2b7abac9be00fd5f7b00ad28f4 Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 16 Sep 2016 10:35:46 -0700 Subject: [PATCH 056/210] Ugly serialization fix to identify other issues - I am comminting this in a different branch and I will fix it in a proper way. --- .../PersistentSessionTests.cs | 1 - .../DurableTask.ServiceFabric.csproj | 3 + .../PersistentSession.cs | 36 +- .../PersistentSession.generated.cs | 371 ++++++++++++++++++ 4 files changed, 405 insertions(+), 6 deletions(-) create mode 100644 src/DurableTask.ServiceFabric/PersistentSession.generated.cs diff --git a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs index 07d825cc5..9d46fb770 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs @@ -26,7 +26,6 @@ namespace DurableTask.ServiceFabric.UnitTests public class PersistentSessionTests { [TestMethod] - [Ignore] //Todo public void SerializationTest() { int numberOfItemsInCollections = 2; diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 350e51ee5..1ce3907e7 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -98,6 +98,9 @@ MSBuild:GenerateCodeFromAttributes + + PersistentSession.cs + diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index 0333d02bd..8f51a4085 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -12,6 +12,7 @@ // ---------------------------------------------------------------------------------- using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Runtime.Serialization; using DurableTask.History; @@ -19,22 +20,31 @@ namespace DurableTask.ServiceFabric { - [GenerateImmutable(GenerateBuilder = true)] + //[GenerateImmutable(GenerateBuilder = true)] [DataContract] public sealed partial class PersistentSession { [DataMember] readonly string sessionId; + //readonly ImmutableList sessionState; + private ImmutableList sessionState; + + //readonly ImmutableList messages; + private ImmutableList messages; + + //readonly ImmutableList scheduledMessages; + private ImmutableList scheduledMessages; + //Todo: Is this performant? Perhaps consider json serialization instead? [DataMember] - readonly ImmutableList sessionState; + private IEnumerable SessionStateWrapper { get; set; } [DataMember] - readonly ImmutableList messages; + private IEnumerable MessagesWrapper { get; set; } [DataMember] - readonly ImmutableList scheduledMessages; + private IEnumerable ScheduledMessagesWrapper { get; set; } static partial void CreateDefaultTemplate(ref Template template) { @@ -42,9 +52,25 @@ static partial void CreateDefaultTemplate(ref Template template) template.ScheduledMessages = ImmutableList.Empty; template.SessionState = ImmutableList.Empty; } + + [OnDeserialized] + private void OnDeserialized(StreamingContext context) + { + this.sessionState = this.SessionStateWrapper.ToImmutableList(); + this.messages = this.MessagesWrapper.ToImmutableList(); + this.scheduledMessages = this.ScheduledMessagesWrapper.ToImmutableList(); + } + + [OnSerializing] + private void OnSerializing(StreamingContext context) + { + this.SessionStateWrapper = this.sessionState; + this.MessagesWrapper = this.messages; + this.ScheduledMessagesWrapper = this.scheduledMessages; + } } - [GenerateImmutable(GenerateBuilder = true)] + //[GenerateImmutable(GenerateBuilder = true)] [DataContract] public sealed partial class ReceivableTaskMessage { diff --git a/src/DurableTask.ServiceFabric/PersistentSession.generated.cs b/src/DurableTask.ServiceFabric/PersistentSession.generated.cs new file mode 100644 index 000000000..b703940dd --- /dev/null +++ b/src/DurableTask.ServiceFabric/PersistentSession.generated.cs @@ -0,0 +1,371 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Immutable; +using System.Runtime.Serialization; +using DurableTask.History; +using ImmutableObjectGraph.Generation; + +namespace DurableTask.ServiceFabric +{ + partial class PersistentSession + { + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + private static readonly PersistentSession DefaultInstance = GetDefaultTemplate(); + private static int lastIdentityProduced; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + private readonly uint identity; + [System.ObsoleteAttribute("This constructor for use with deserializers only. Use the static Create factory method instead.")] + public PersistentSession(System.String SessionId, System.Collections.Immutable.ImmutableList SessionState, System.Collections.Immutable.ImmutableList Messages, System.Collections.Immutable.ImmutableList ScheduledMessages, System.Boolean IsLocked) : this(NewIdentity(), sessionId: SessionId, sessionState: SessionState, messages: Messages, scheduledMessages: ScheduledMessages, isLocked: IsLocked, skipValidation: false) + { + } + + PersistentSession(uint identity, System.String sessionId, System.Collections.Immutable.ImmutableList sessionState, System.Collections.Immutable.ImmutableList messages, System.Collections.Immutable.ImmutableList scheduledMessages, System.Boolean isLocked, bool skipValidation) + { + this.identity = identity; + this.sessionId = sessionId; + this.sessionState = sessionState; + this.messages = messages; + this.scheduledMessages = scheduledMessages; + this.isLocked = isLocked; + if (!skipValidation) + { + this.Validate(); + } + } + + public bool IsLocked => this.isLocked; + public ImmutableList Messages => this.messages; + public ImmutableList ScheduledMessages => this.scheduledMessages; + public string SessionId => this.sessionId; + public ImmutableList SessionState => this.sessionState; + internal uint Identity => this.identity; + public static PersistentSession Create(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional)) + { + var identity = ImmutableObjectGraph.Optional.For(NewIdentity()); + return DefaultInstance.WithFactory(sessionId: ImmutableObjectGraph.Optional.For(sessionId.GetValueOrDefault(DefaultInstance.SessionId)), sessionState: ImmutableObjectGraph.Optional.For(sessionState.GetValueOrDefault(DefaultInstance.SessionState)), messages: ImmutableObjectGraph.Optional.For(messages.GetValueOrDefault(DefaultInstance.Messages)), scheduledMessages: ImmutableObjectGraph.Optional.For(scheduledMessages.GetValueOrDefault(DefaultInstance.ScheduledMessages)), isLocked: ImmutableObjectGraph.Optional.For(isLocked.GetValueOrDefault(DefaultInstance.IsLocked)), identity: identity); + } + + public static Builder CreateBuilder() => new Builder(DefaultInstance); + public Builder ToBuilder() => new Builder(this); + public PersistentSession With(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional)) + { + return (PersistentSession)this.WithCore(sessionId: sessionId, sessionState: sessionState, messages: messages, scheduledMessages: scheduledMessages, isLocked: isLocked); + } + + static partial void CreateDefaultTemplate(ref Template template); + private static PersistentSession GetDefaultTemplate() + { + var template = new Template(); + CreateDefaultTemplate(ref template); + return new PersistentSession(default(uint), template.SessionId, template.SessionState, template.Messages, template.ScheduledMessages, template.IsLocked, skipValidation: true); + } + + static uint NewIdentity() + { + return (uint)System.Threading.Interlocked.Increment(ref lastIdentityProduced); + } + + partial void Validate(); + PersistentSession WithCore(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional)) + { + return this.WithFactory(sessionId: sessionId, sessionState: sessionState, messages: messages, scheduledMessages: scheduledMessages, isLocked: isLocked, identity: ImmutableObjectGraph.Optional.For(this.Identity)); + } + + private PersistentSession WithFactory(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional identity = default(ImmutableObjectGraph.Optional)) + { + if ((identity.IsDefined && identity.Value != this.Identity) || (sessionId.IsDefined && sessionId.Value != this.SessionId) || (sessionState.IsDefined && sessionState.Value != this.SessionState) || (messages.IsDefined && messages.Value != this.Messages) || (scheduledMessages.IsDefined && scheduledMessages.Value != this.ScheduledMessages) || (isLocked.IsDefined && isLocked.Value != this.IsLocked)) + { + return new PersistentSession(identity: identity.GetValueOrDefault(this.Identity), sessionId: sessionId.GetValueOrDefault(this.SessionId), sessionState: sessionState.GetValueOrDefault(this.SessionState), messages: messages.GetValueOrDefault(this.Messages), scheduledMessages: scheduledMessages.GetValueOrDefault(this.ScheduledMessages), isLocked: isLocked.GetValueOrDefault(this.IsLocked), skipValidation: false); + } + else + { + return this; + } + } + + public partial class Builder : System.ComponentModel.INotifyPropertyChanged + { + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected System.Boolean isLocked; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected System.Collections.Immutable.ImmutableList messages; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected System.Collections.Immutable.ImmutableList scheduledMessages; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected System.String sessionId; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected System.Collections.Immutable.ImmutableList sessionState; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + private PersistentSession immutable; + internal Builder(PersistentSession immutable) + { + this.immutable = immutable; + this.sessionId = immutable.sessionId; + this.sessionState = immutable.sessionState; + this.messages = immutable.messages; + this.scheduledMessages = immutable.scheduledMessages; + this.isLocked = immutable.isLocked; + } + + public System.Boolean IsLocked + { + get + { + return this.isLocked; + } + + set + { + if (this.isLocked != value) + { + this.isLocked = value; + this.OnPropertyChanged(); + } + } + } + + public System.Collections.Immutable.ImmutableList Messages + { + get + { + return this.messages; + } + + set + { + if (this.messages != value) + { + this.messages = value; + this.OnPropertyChanged(); + } + } + } + + public System.Collections.Immutable.ImmutableList ScheduledMessages + { + get + { + return this.scheduledMessages; + } + + set + { + if (this.scheduledMessages != value) + { + this.scheduledMessages = value; + this.OnPropertyChanged(); + } + } + } + + public System.String SessionId + { + get + { + return this.sessionId; + } + + set + { + if (this.sessionId != value) + { + this.sessionId = value; + this.OnPropertyChanged(); + } + } + } + + public System.Collections.Immutable.ImmutableList SessionState + { + get + { + return this.sessionState; + } + + set + { + if (this.sessionState != value) + { + this.sessionState = value; + this.OnPropertyChanged(); + } + } + } + + public PersistentSession ToImmutable() + { + return this.immutable = this.immutable.With(ImmutableObjectGraph.Optional.For(this.SessionId), ImmutableObjectGraph.Optional.For(this.SessionState), ImmutableObjectGraph.Optional.For(this.Messages), ImmutableObjectGraph.Optional.For(this.ScheduledMessages), ImmutableObjectGraph.Optional.For(this.IsLocked)); + } + + protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberNameAttribute] string propertyName = "") + { + this.PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + } + +#pragma warning disable 649 // field initialization is optional in user code + + private struct Template + { + internal System.Boolean IsLocked; + internal System.Collections.Immutable.ImmutableList Messages; + internal System.Collections.Immutable.ImmutableList ScheduledMessages; + internal System.String SessionId; + internal System.Collections.Immutable.ImmutableList SessionState; + } +#pragma warning restore 649 + } +} + +namespace DurableTask.ServiceFabric +{ + partial class ReceivableTaskMessage + { + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + private static readonly ReceivableTaskMessage DefaultInstance = GetDefaultTemplate(); + private static int lastIdentityProduced; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + private readonly uint identity; + [System.ObsoleteAttribute("This constructor for use with deserializers only. Use the static Create factory method instead.")] + public ReceivableTaskMessage(DurableTask.TaskMessage TaskMessage, System.Boolean IsReceived) : this(NewIdentity(), taskMessage: TaskMessage, isReceived: IsReceived, skipValidation: false) + { + } + + ReceivableTaskMessage(uint identity, DurableTask.TaskMessage taskMessage, System.Boolean isReceived, bool skipValidation) + { + this.identity = identity; + this.taskMessage = taskMessage; + this.isReceived = isReceived; + if (!skipValidation) + { + this.Validate(); + } + } + + public bool IsReceived => this.isReceived; + public TaskMessage TaskMessage => this.taskMessage; + internal uint Identity => this.identity; + public static ReceivableTaskMessage Create(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional)) + { + var identity = ImmutableObjectGraph.Optional.For(NewIdentity()); + return DefaultInstance.WithFactory(taskMessage: ImmutableObjectGraph.Optional.For(taskMessage.GetValueOrDefault(DefaultInstance.TaskMessage)), isReceived: ImmutableObjectGraph.Optional.For(isReceived.GetValueOrDefault(DefaultInstance.IsReceived)), identity: identity); + } + + public static Builder CreateBuilder() => new Builder(DefaultInstance); + public Builder ToBuilder() => new Builder(this); + public ReceivableTaskMessage With(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional)) + { + return (ReceivableTaskMessage)this.WithCore(taskMessage: taskMessage, isReceived: isReceived); + } + + static partial void CreateDefaultTemplate(ref Template template); + private static ReceivableTaskMessage GetDefaultTemplate() + { + var template = new Template(); + CreateDefaultTemplate(ref template); + return new ReceivableTaskMessage(default(uint), template.TaskMessage, template.IsReceived, skipValidation: true); + } + + static uint NewIdentity() + { + return (uint)System.Threading.Interlocked.Increment(ref lastIdentityProduced); + } + + partial void Validate(); + ReceivableTaskMessage WithCore(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional)) + { + return this.WithFactory(taskMessage: taskMessage, isReceived: isReceived, identity: ImmutableObjectGraph.Optional.For(this.Identity)); + } + + private ReceivableTaskMessage WithFactory(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional identity = default(ImmutableObjectGraph.Optional)) + { + if ((identity.IsDefined && identity.Value != this.Identity) || (taskMessage.IsDefined && taskMessage.Value != this.TaskMessage) || (isReceived.IsDefined && isReceived.Value != this.IsReceived)) + { + return new ReceivableTaskMessage(identity: identity.GetValueOrDefault(this.Identity), taskMessage: taskMessage.GetValueOrDefault(this.TaskMessage), isReceived: isReceived.GetValueOrDefault(this.IsReceived), skipValidation: false); + } + else + { + return this; + } + } + + public partial class Builder : System.ComponentModel.INotifyPropertyChanged + { + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected System.Boolean isReceived; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected DurableTask.TaskMessage taskMessage; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + private ReceivableTaskMessage immutable; + internal Builder(ReceivableTaskMessage immutable) + { + this.immutable = immutable; + this.taskMessage = immutable.taskMessage; + this.isReceived = immutable.isReceived; + } + + public System.Boolean IsReceived + { + get + { + return this.isReceived; + } + + set + { + if (this.isReceived != value) + { + this.isReceived = value; + this.OnPropertyChanged(); + } + } + } + + public DurableTask.TaskMessage TaskMessage + { + get + { + return this.taskMessage; + } + + set + { + if (this.taskMessage != value) + { + this.taskMessage = value; + this.OnPropertyChanged(); + } + } + } + + public ReceivableTaskMessage ToImmutable() + { + return this.immutable = this.immutable.With(ImmutableObjectGraph.Optional.For(this.TaskMessage), ImmutableObjectGraph.Optional.For(this.IsReceived)); + } + + protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberNameAttribute] string propertyName = "") + { + this.PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + } + +#pragma warning disable 649 // field initialization is optional in user code + + private struct Template + { + internal System.Boolean IsReceived; + internal DurableTask.TaskMessage TaskMessage; + } +#pragma warning restore 649 + } +} \ No newline at end of file From e0e9d81af93154afc9c0994a3b176c2f1190d6b1 Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 16 Sep 2016 10:35:46 -0700 Subject: [PATCH 057/210] May not have optimizations for memory but something that might work... --- .../PersistentSessionTests.cs | 5 +- .../DurableTask.ServiceFabric.csproj | 3 - .../PersistentSession.api.cs | 48 +-- .../PersistentSession.cs | 61 +-- .../PersistentSession.generated.cs | 371 ------------------ .../SessionsProvider.cs | 2 +- 6 files changed, 57 insertions(+), 433 deletions(-) delete mode 100644 src/DurableTask.ServiceFabric/PersistentSession.generated.cs diff --git a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs index 9d46fb770..cefd8be7e 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs @@ -16,6 +16,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.IO; +using System.Linq; using System.Runtime.Serialization; using DurableTask.History; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -72,8 +73,8 @@ public void SerializationTest() Assert.AreEqual("testSession", deserialized.SessionId); Assert.IsFalse(deserialized.IsLocked); Assert.AreEqual(numberOfItemsInCollections*2 + 2, deserialized.SessionState.Count); - Assert.AreEqual(numberOfItemsInCollections, deserialized.Messages.Count); - Assert.AreEqual(numberOfItemsInCollections, deserialized.ScheduledMessages.Count); + Assert.AreEqual(numberOfItemsInCollections, deserialized.Messages.ToList().Count); + Assert.AreEqual(numberOfItemsInCollections, deserialized.ScheduledMessages.ToList().Count); } } } diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 1ce3907e7..350e51ee5 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -98,9 +98,6 @@ MSBuild:GenerateCodeFromAttributes - - PersistentSession.cs - diff --git a/src/DurableTask.ServiceFabric/PersistentSession.api.cs b/src/DurableTask.ServiceFabric/PersistentSession.api.cs index ea4cc1db5..2cb6ae9e8 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.api.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.api.cs @@ -24,13 +24,12 @@ public sealed partial class PersistentSession // Todo: Can optimize in a few other ways, for now, something that works public PersistentSession FireScheduledMessages() { - var builder = this.ToBuilder(); - var messagesBuilder = builder.Messages.ToBuilder(); - var scheduledMessagesBuilder = builder.ScheduledMessages.ToBuilder(); + var messagesBuilder = this.Messages.ToImmutableList().ToBuilder(); + var remainingScheduledMessagesBuilder = ImmutableList.Empty.ToBuilder(); var currentTime = DateTime.UtcNow; - foreach (var scheduledMessage in builder.ScheduledMessages) + foreach (var scheduledMessage in this.ScheduledMessages) { var timerEvent = scheduledMessage.TaskMessage.Event as TimerFiredEvent; @@ -43,61 +42,56 @@ public PersistentSession FireScheduledMessages() if (timerEvent.FireAt <= currentTime) { messagesBuilder.Add(scheduledMessage); - //Todo: Is Remove O(N) or O(1)? If former, it's better to just maintain a new remaining scheduled messages collection instead? - scheduledMessagesBuilder.Remove(scheduledMessage); + } + else + { + remainingScheduledMessagesBuilder.Add(scheduledMessage); } } - builder.Messages = messagesBuilder.ToImmutable(); - builder.ScheduledMessages = scheduledMessagesBuilder.ToImmutable(); - - return builder.ToImmutable(); + return Create(this.SessionId, this.SessionState, messagesBuilder.ToImmutableList(), remainingScheduledMessagesBuilder.ToImmutableList(), this.IsLocked); } public PersistentSession ReceiveMessages() { - var builder = this.ToBuilder(); - //Todo: Experiment (measure memory for ConvertAll on builder vs SelectMany on immutable - builder.Messages = builder.Messages.ToBuilder().ConvertAll(m => m.With(isReceived: true)); - return builder.ToImmutable(); + var messages = this.Messages.ToImmutableList().ToBuilder().ConvertAll(m => ReceivableTaskMessage.Create(m.TaskMessage, isReceived: true)); + return Create(this.SessionId, this.SessionState, messages, this.ScheduledMessages, isLocked: true); } public PersistentSession CompleteMessages(OrchestrationRuntimeState newState, IList newScheduledMessages) { - var builder = this.ToBuilder(); - builder.Messages = builder.Messages.RemoveAll(m => m.IsReceived); - builder.SessionState = newState?.Events.ToImmutableList(); + var messages = this.Messages.ToImmutableList().RemoveAll(m => m.IsReceived); + var sessionState = newState?.Events.ToImmutableList(); + var scheduledMessages = this.ScheduledMessages; if (newScheduledMessages?.Count > 0) { - builder.ScheduledMessages = builder.ScheduledMessages.AddRange(newScheduledMessages.Select(tm => ReceivableTaskMessage.Create(tm))); + scheduledMessages = this.ScheduledMessages.ToImmutableList().AddRange(newScheduledMessages.Select(tm => ReceivableTaskMessage.Create(tm))); } - return builder.ToImmutable(); + return Create(this.SessionId, sessionState, messages, scheduledMessages, isLocked: false); } public PersistentSession AppendMessage(TaskMessage message) { - var builder = this.ToBuilder(); - builder.Messages = builder.Messages.Add(ReceivableTaskMessage.Create(message)); - return builder.ToImmutable(); + var messages = this.Messages.ToImmutableList().Add(ReceivableTaskMessage.Create(message)); + return Create(this.SessionId, this.SessionState, messages, this.ScheduledMessages, this.IsLocked); } public PersistentSession AppendMessageBatch(IEnumerable newMessages) { - var builder = this.ToBuilder(); - builder.Messages = builder.Messages.AddRange(newMessages.Select(m => ReceivableTaskMessage.Create(m))); - return builder.ToImmutable(); + var messages = this.Messages.ToImmutableList().AddRange(newMessages.Select(m => ReceivableTaskMessage.Create(m))); + return Create(this.SessionId, this.SessionState, messages, this.ScheduledMessages, this.IsLocked); } public static PersistentSession CreateWithNewMessage(string sessionId, TaskMessage newMessage) { var messages = ImmutableList.Empty.Add(ReceivableTaskMessage.Create(newMessage)); - return PersistentSession.Create(sessionId, messages: messages); + return PersistentSession.Create(sessionId, sessionState: null, messages: messages, scheduledMessages: null, isLocked: false); } public static PersistentSession CreateWithNewMessages(string sessionId, IEnumerable newMessages) { var messages = ImmutableList.Empty.AddRange(newMessages.Select(newMessage => ReceivableTaskMessage.Create(newMessage))); - return PersistentSession.Create(sessionId, messages: messages); + return PersistentSession.Create(sessionId, sessionState: null, messages: messages, scheduledMessages: null, isLocked: false); } } } diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index 8f51a4085..5eea952ae 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -25,48 +25,40 @@ namespace DurableTask.ServiceFabric public sealed partial class PersistentSession { [DataMember] - readonly string sessionId; - - //readonly ImmutableList sessionState; - private ImmutableList sessionState; - - //readonly ImmutableList messages; - private ImmutableList messages; - - //readonly ImmutableList scheduledMessages; - private ImmutableList scheduledMessages; + public string SessionId { get; private set; } //Todo: Is this performant? Perhaps consider json serialization instead? [DataMember] - private IEnumerable SessionStateWrapper { get; set; } + public IList SessionState { get; private set; } [DataMember] - private IEnumerable MessagesWrapper { get; set; } + public IEnumerable Messages { get; private set; } [DataMember] - private IEnumerable ScheduledMessagesWrapper { get; set; } + public IEnumerable ScheduledMessages { get; private set; } - static partial void CreateDefaultTemplate(ref Template template) - { - template.Messages = ImmutableList.Empty; - template.ScheduledMessages = ImmutableList.Empty; - template.SessionState = ImmutableList.Empty; - } + public bool IsLocked { get; private set; } [OnDeserialized] private void OnDeserialized(StreamingContext context) { - this.sessionState = this.SessionStateWrapper.ToImmutableList(); - this.messages = this.MessagesWrapper.ToImmutableList(); - this.scheduledMessages = this.ScheduledMessagesWrapper.ToImmutableList(); + this.SessionState = this.SessionState.ToImmutableList(); + this.Messages = this.Messages.ToImmutableList(); + this.ScheduledMessages = this.ScheduledMessages.ToImmutableList(); + } + + private PersistentSession(string sessionId, IList sessionState, IEnumerable messages, IEnumerable scheduledMessages, bool isLocked) + { + this.SessionId = sessionId; + this.SessionState = sessionState ?? ImmutableList.Empty; + this.Messages = messages ?? ImmutableList.Empty; + this.ScheduledMessages = scheduledMessages ?? ImmutableList.Empty; + this.IsLocked = isLocked; } - [OnSerializing] - private void OnSerializing(StreamingContext context) + public static PersistentSession Create(string sessionId, IList sessionState, IEnumerable messages, IEnumerable scheduledMessages, bool isLocked) { - this.SessionStateWrapper = this.sessionState; - this.MessagesWrapper = this.messages; - this.ScheduledMessagesWrapper = this.scheduledMessages; + return new PersistentSession(sessionId, sessionState, messages, scheduledMessages, isLocked); } } @@ -75,8 +67,19 @@ private void OnSerializing(StreamingContext context) public sealed partial class ReceivableTaskMessage { [DataMember] - readonly TaskMessage taskMessage; + public TaskMessage TaskMessage { get; private set; } + + public bool IsReceived { get; private set; } - readonly bool isReceived; + private ReceivableTaskMessage(TaskMessage taskMessage, bool isReceived) + { + this.TaskMessage = taskMessage; + this.IsReceived = isReceived; + } + + public static ReceivableTaskMessage Create(TaskMessage taskMessage, bool isReceived = false) + { + return new ReceivableTaskMessage(taskMessage, isReceived); + } } } diff --git a/src/DurableTask.ServiceFabric/PersistentSession.generated.cs b/src/DurableTask.ServiceFabric/PersistentSession.generated.cs deleted file mode 100644 index b703940dd..000000000 --- a/src/DurableTask.ServiceFabric/PersistentSession.generated.cs +++ /dev/null @@ -1,371 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// ------------------------------------------------------------------------------ - -using System; -using System.Collections.Immutable; -using System.Runtime.Serialization; -using DurableTask.History; -using ImmutableObjectGraph.Generation; - -namespace DurableTask.ServiceFabric -{ - partial class PersistentSession - { - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - private static readonly PersistentSession DefaultInstance = GetDefaultTemplate(); - private static int lastIdentityProduced; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - private readonly uint identity; - [System.ObsoleteAttribute("This constructor for use with deserializers only. Use the static Create factory method instead.")] - public PersistentSession(System.String SessionId, System.Collections.Immutable.ImmutableList SessionState, System.Collections.Immutable.ImmutableList Messages, System.Collections.Immutable.ImmutableList ScheduledMessages, System.Boolean IsLocked) : this(NewIdentity(), sessionId: SessionId, sessionState: SessionState, messages: Messages, scheduledMessages: ScheduledMessages, isLocked: IsLocked, skipValidation: false) - { - } - - PersistentSession(uint identity, System.String sessionId, System.Collections.Immutable.ImmutableList sessionState, System.Collections.Immutable.ImmutableList messages, System.Collections.Immutable.ImmutableList scheduledMessages, System.Boolean isLocked, bool skipValidation) - { - this.identity = identity; - this.sessionId = sessionId; - this.sessionState = sessionState; - this.messages = messages; - this.scheduledMessages = scheduledMessages; - this.isLocked = isLocked; - if (!skipValidation) - { - this.Validate(); - } - } - - public bool IsLocked => this.isLocked; - public ImmutableList Messages => this.messages; - public ImmutableList ScheduledMessages => this.scheduledMessages; - public string SessionId => this.sessionId; - public ImmutableList SessionState => this.sessionState; - internal uint Identity => this.identity; - public static PersistentSession Create(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional)) - { - var identity = ImmutableObjectGraph.Optional.For(NewIdentity()); - return DefaultInstance.WithFactory(sessionId: ImmutableObjectGraph.Optional.For(sessionId.GetValueOrDefault(DefaultInstance.SessionId)), sessionState: ImmutableObjectGraph.Optional.For(sessionState.GetValueOrDefault(DefaultInstance.SessionState)), messages: ImmutableObjectGraph.Optional.For(messages.GetValueOrDefault(DefaultInstance.Messages)), scheduledMessages: ImmutableObjectGraph.Optional.For(scheduledMessages.GetValueOrDefault(DefaultInstance.ScheduledMessages)), isLocked: ImmutableObjectGraph.Optional.For(isLocked.GetValueOrDefault(DefaultInstance.IsLocked)), identity: identity); - } - - public static Builder CreateBuilder() => new Builder(DefaultInstance); - public Builder ToBuilder() => new Builder(this); - public PersistentSession With(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional)) - { - return (PersistentSession)this.WithCore(sessionId: sessionId, sessionState: sessionState, messages: messages, scheduledMessages: scheduledMessages, isLocked: isLocked); - } - - static partial void CreateDefaultTemplate(ref Template template); - private static PersistentSession GetDefaultTemplate() - { - var template = new Template(); - CreateDefaultTemplate(ref template); - return new PersistentSession(default(uint), template.SessionId, template.SessionState, template.Messages, template.ScheduledMessages, template.IsLocked, skipValidation: true); - } - - static uint NewIdentity() - { - return (uint)System.Threading.Interlocked.Increment(ref lastIdentityProduced); - } - - partial void Validate(); - PersistentSession WithCore(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional)) - { - return this.WithFactory(sessionId: sessionId, sessionState: sessionState, messages: messages, scheduledMessages: scheduledMessages, isLocked: isLocked, identity: ImmutableObjectGraph.Optional.For(this.Identity)); - } - - private PersistentSession WithFactory(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional identity = default(ImmutableObjectGraph.Optional)) - { - if ((identity.IsDefined && identity.Value != this.Identity) || (sessionId.IsDefined && sessionId.Value != this.SessionId) || (sessionState.IsDefined && sessionState.Value != this.SessionState) || (messages.IsDefined && messages.Value != this.Messages) || (scheduledMessages.IsDefined && scheduledMessages.Value != this.ScheduledMessages) || (isLocked.IsDefined && isLocked.Value != this.IsLocked)) - { - return new PersistentSession(identity: identity.GetValueOrDefault(this.Identity), sessionId: sessionId.GetValueOrDefault(this.SessionId), sessionState: sessionState.GetValueOrDefault(this.SessionState), messages: messages.GetValueOrDefault(this.Messages), scheduledMessages: scheduledMessages.GetValueOrDefault(this.ScheduledMessages), isLocked: isLocked.GetValueOrDefault(this.IsLocked), skipValidation: false); - } - else - { - return this; - } - } - - public partial class Builder : System.ComponentModel.INotifyPropertyChanged - { - public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected System.Boolean isLocked; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected System.Collections.Immutable.ImmutableList messages; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected System.Collections.Immutable.ImmutableList scheduledMessages; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected System.String sessionId; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected System.Collections.Immutable.ImmutableList sessionState; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - private PersistentSession immutable; - internal Builder(PersistentSession immutable) - { - this.immutable = immutable; - this.sessionId = immutable.sessionId; - this.sessionState = immutable.sessionState; - this.messages = immutable.messages; - this.scheduledMessages = immutable.scheduledMessages; - this.isLocked = immutable.isLocked; - } - - public System.Boolean IsLocked - { - get - { - return this.isLocked; - } - - set - { - if (this.isLocked != value) - { - this.isLocked = value; - this.OnPropertyChanged(); - } - } - } - - public System.Collections.Immutable.ImmutableList Messages - { - get - { - return this.messages; - } - - set - { - if (this.messages != value) - { - this.messages = value; - this.OnPropertyChanged(); - } - } - } - - public System.Collections.Immutable.ImmutableList ScheduledMessages - { - get - { - return this.scheduledMessages; - } - - set - { - if (this.scheduledMessages != value) - { - this.scheduledMessages = value; - this.OnPropertyChanged(); - } - } - } - - public System.String SessionId - { - get - { - return this.sessionId; - } - - set - { - if (this.sessionId != value) - { - this.sessionId = value; - this.OnPropertyChanged(); - } - } - } - - public System.Collections.Immutable.ImmutableList SessionState - { - get - { - return this.sessionState; - } - - set - { - if (this.sessionState != value) - { - this.sessionState = value; - this.OnPropertyChanged(); - } - } - } - - public PersistentSession ToImmutable() - { - return this.immutable = this.immutable.With(ImmutableObjectGraph.Optional.For(this.SessionId), ImmutableObjectGraph.Optional.For(this.SessionState), ImmutableObjectGraph.Optional.For(this.Messages), ImmutableObjectGraph.Optional.For(this.ScheduledMessages), ImmutableObjectGraph.Optional.For(this.IsLocked)); - } - - protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberNameAttribute] string propertyName = "") - { - this.PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); - } - } - -#pragma warning disable 649 // field initialization is optional in user code - - private struct Template - { - internal System.Boolean IsLocked; - internal System.Collections.Immutable.ImmutableList Messages; - internal System.Collections.Immutable.ImmutableList ScheduledMessages; - internal System.String SessionId; - internal System.Collections.Immutable.ImmutableList SessionState; - } -#pragma warning restore 649 - } -} - -namespace DurableTask.ServiceFabric -{ - partial class ReceivableTaskMessage - { - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - private static readonly ReceivableTaskMessage DefaultInstance = GetDefaultTemplate(); - private static int lastIdentityProduced; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - private readonly uint identity; - [System.ObsoleteAttribute("This constructor for use with deserializers only. Use the static Create factory method instead.")] - public ReceivableTaskMessage(DurableTask.TaskMessage TaskMessage, System.Boolean IsReceived) : this(NewIdentity(), taskMessage: TaskMessage, isReceived: IsReceived, skipValidation: false) - { - } - - ReceivableTaskMessage(uint identity, DurableTask.TaskMessage taskMessage, System.Boolean isReceived, bool skipValidation) - { - this.identity = identity; - this.taskMessage = taskMessage; - this.isReceived = isReceived; - if (!skipValidation) - { - this.Validate(); - } - } - - public bool IsReceived => this.isReceived; - public TaskMessage TaskMessage => this.taskMessage; - internal uint Identity => this.identity; - public static ReceivableTaskMessage Create(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional)) - { - var identity = ImmutableObjectGraph.Optional.For(NewIdentity()); - return DefaultInstance.WithFactory(taskMessage: ImmutableObjectGraph.Optional.For(taskMessage.GetValueOrDefault(DefaultInstance.TaskMessage)), isReceived: ImmutableObjectGraph.Optional.For(isReceived.GetValueOrDefault(DefaultInstance.IsReceived)), identity: identity); - } - - public static Builder CreateBuilder() => new Builder(DefaultInstance); - public Builder ToBuilder() => new Builder(this); - public ReceivableTaskMessage With(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional)) - { - return (ReceivableTaskMessage)this.WithCore(taskMessage: taskMessage, isReceived: isReceived); - } - - static partial void CreateDefaultTemplate(ref Template template); - private static ReceivableTaskMessage GetDefaultTemplate() - { - var template = new Template(); - CreateDefaultTemplate(ref template); - return new ReceivableTaskMessage(default(uint), template.TaskMessage, template.IsReceived, skipValidation: true); - } - - static uint NewIdentity() - { - return (uint)System.Threading.Interlocked.Increment(ref lastIdentityProduced); - } - - partial void Validate(); - ReceivableTaskMessage WithCore(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional)) - { - return this.WithFactory(taskMessage: taskMessage, isReceived: isReceived, identity: ImmutableObjectGraph.Optional.For(this.Identity)); - } - - private ReceivableTaskMessage WithFactory(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional identity = default(ImmutableObjectGraph.Optional)) - { - if ((identity.IsDefined && identity.Value != this.Identity) || (taskMessage.IsDefined && taskMessage.Value != this.TaskMessage) || (isReceived.IsDefined && isReceived.Value != this.IsReceived)) - { - return new ReceivableTaskMessage(identity: identity.GetValueOrDefault(this.Identity), taskMessage: taskMessage.GetValueOrDefault(this.TaskMessage), isReceived: isReceived.GetValueOrDefault(this.IsReceived), skipValidation: false); - } - else - { - return this; - } - } - - public partial class Builder : System.ComponentModel.INotifyPropertyChanged - { - public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected System.Boolean isReceived; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected DurableTask.TaskMessage taskMessage; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - private ReceivableTaskMessage immutable; - internal Builder(ReceivableTaskMessage immutable) - { - this.immutable = immutable; - this.taskMessage = immutable.taskMessage; - this.isReceived = immutable.isReceived; - } - - public System.Boolean IsReceived - { - get - { - return this.isReceived; - } - - set - { - if (this.isReceived != value) - { - this.isReceived = value; - this.OnPropertyChanged(); - } - } - } - - public DurableTask.TaskMessage TaskMessage - { - get - { - return this.taskMessage; - } - - set - { - if (this.taskMessage != value) - { - this.taskMessage = value; - this.OnPropertyChanged(); - } - } - } - - public ReceivableTaskMessage ToImmutable() - { - return this.immutable = this.immutable.With(ImmutableObjectGraph.Optional.For(this.TaskMessage), ImmutableObjectGraph.Optional.For(this.IsReceived)); - } - - protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberNameAttribute] string propertyName = "") - { - this.PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); - } - } - -#pragma warning disable 649 // field initialization is optional in user code - - private struct Template - { - internal System.Boolean IsReceived; - internal DurableTask.TaskMessage TaskMessage; - } -#pragma warning restore 649 - } -} \ No newline at end of file diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index e2a0cf275..82c1f7238 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -28,7 +28,7 @@ class SessionsProvider IReliableDictionary orchestrations; CancellationTokenSource cancellationTokenSource; - readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId); + readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId, null, null, null, false); public SessionsProvider(IReliableStateManager stateManager, IReliableDictionary orchestrations) { From fdbb680df331cfb060395ce22057214bb140f1c1 Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 16 Sep 2016 10:35:46 -0700 Subject: [PATCH 058/210] A reasonable (according to me) compromise to keep the class immutable (in spirit) and make data contract serialization work. (For reliability over node failures) [The other choices are : - to use the same code generation for immutable and use some other serialization technique and write winfab state serializer for that serialization mechanism - or avoid using immutable and risk introducing hard to catch bugs Also, the performance of data contract serialization doesn't seem to be too bad - hence I removed the comment. If we see that serialization is indeed bottleneck when we do perf testing, we can fix that. --- ...DurableTask.ServiceFabric.UnitTests.csproj | 13 ++------ .../PersistentSessionTests.cs | 6 ++-- .../app.config | 4 +++ .../packages.config | 11 +------ .../DurableTask.ServiceFabric.csproj | 23 +------------ .../FabricOrchestrationService.cs | 5 +-- .../PersistentSession.api.cs | 29 +++++++++------- .../PersistentSession.cs | 33 ++++++++++--------- src/DurableTask.ServiceFabric/packages.config | 12 +------ 9 files changed, 52 insertions(+), 84 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.UnitTests/DurableTask.ServiceFabric.UnitTests.csproj b/Test/DurableTask.ServiceFabric.UnitTests/DurableTask.ServiceFabric.UnitTests.csproj index 98c8c0027..653d4e406 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/DurableTask.ServiceFabric.UnitTests.csproj +++ b/Test/DurableTask.ServiceFabric.UnitTests/DurableTask.ServiceFabric.UnitTests.csproj @@ -30,13 +30,10 @@ 4 - - ..\..\packages\ImmutableObjectGraph.1.1.98-beta\lib\dotnet\ImmutableObjectGraph.dll - True - - - ..\..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll + + False + ..\..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll True @@ -48,10 +45,6 @@ - - ..\..\packages\Validation.2.2.8\lib\dotnet\Validation.dll - True - diff --git a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs index cefd8be7e..d386cfa8c 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs @@ -72,9 +72,9 @@ public void SerializationTest() Assert.IsNotNull(deserialized); Assert.AreEqual("testSession", deserialized.SessionId); Assert.IsFalse(deserialized.IsLocked); - Assert.AreEqual(numberOfItemsInCollections*2 + 2, deserialized.SessionState.Count); - Assert.AreEqual(numberOfItemsInCollections, deserialized.Messages.ToList().Count); - Assert.AreEqual(numberOfItemsInCollections, deserialized.ScheduledMessages.ToList().Count); + Assert.AreEqual(numberOfItemsInCollections*2 + 2, deserialized.SessionState.Count()); + Assert.AreEqual(numberOfItemsInCollections, deserialized.Messages.Count()); + Assert.AreEqual(numberOfItemsInCollections, deserialized.ScheduledMessages.Count()); } } } diff --git a/Test/DurableTask.ServiceFabric.UnitTests/app.config b/Test/DurableTask.ServiceFabric.UnitTests/app.config index 195db1f42..bb6a63439 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/app.config +++ b/Test/DurableTask.ServiceFabric.UnitTests/app.config @@ -6,6 +6,10 @@ + + + + \ No newline at end of file diff --git a/Test/DurableTask.ServiceFabric.UnitTests/packages.config b/Test/DurableTask.ServiceFabric.UnitTests/packages.config index a5a743bc5..54d145ca3 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/packages.config +++ b/Test/DurableTask.ServiceFabric.UnitTests/packages.config @@ -1,15 +1,6 @@  - - - - + - - - - - - \ No newline at end of file diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 350e51ee5..28197568e 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -32,14 +32,6 @@ 4 - - ..\..\packages\ImmutableObjectGraph.1.1.98-beta\lib\dotnet\ImmutableObjectGraph.dll - True - - - ..\..\packages\ImmutableObjectGraph.Generation.1.1.98-beta\lib\dotnet\ImmutableObjectGraph.Generation.Attributes.dll - True - ..\..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll True @@ -64,7 +56,7 @@ False - ..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + ..\..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll True @@ -79,10 +71,6 @@ - - ..\..\packages\Validation.2.2.8\lib\dotnet\Validation.dll - True - @@ -115,15 +103,6 @@ - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - + \ No newline at end of file diff --git a/DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs b/DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..61fc9be86 --- /dev/null +++ b/DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DurableTask.ServiceFabric.Test")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DurableTask.ServiceFabric.Test")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("edc63ddb-8397-4aec-bf54-6395b2527075")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj new file mode 100644 index 000000000..914fea431 --- /dev/null +++ b/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -0,0 +1,77 @@ + + + + + Debug + AnyCPU + {5C617B24-4902-4992-8F71-AB14F00B74A8} + Library + Properties + DurableTask.ServiceFabric + DurableTask.ServiceFabric + v4.5.2 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll + True + + + ..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll + True + + + ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.dll + True + + + ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll + True + + + + + ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\System.Fabric.dll + True + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs b/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..c2c980c3e --- /dev/null +++ b/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DurableTask.ServiceFabric")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DurableTask.ServiceFabric")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5c617b24-4902-4992-8f71-ab14f00b74a8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DurableTask.ServiceFabric/packages.config b/DurableTask.ServiceFabric/packages.config new file mode 100644 index 000000000..99d0248fb --- /dev/null +++ b/DurableTask.ServiceFabric/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From c24a1c27590c1fffbd726cb20c3de3239235a7c3 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 062/210] A simple peek lock implementation on sessions. What's not done is automatic lock exipry. (The session is not unlocked till Complete is called after an Accept is done and that means no one will see it) --- .../TestStatefulService.cs | 5 +- .../FabricOrchestrationService.cs | 6 +- .../FabricOrchestrationServiceClient.cs | 22 +-- .../PersistentSession.api.cs | 20 +++ .../SessionsProvider.cs | 125 ++++++++++-------- 5 files changed, 99 insertions(+), 79 deletions(-) diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index f3332a4bb..c30e28189 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -45,8 +45,9 @@ public TestStatefulService(StatefulServiceContext context) : base(context) { var instanceStore = new FabricOrchestrationInstanceStore(this.StateManager); - this.worker = new TaskHubWorker(new FabricOrchestrationService(this.StateManager, instanceStore)); - this.client = new TaskHubClient(new FabricOrchestrationServiceClient(this.StateManager, instanceStore)); + var sessionProvider = new SessionsProvider(this.StateManager); + this.worker = new TaskHubWorker(new FabricOrchestrationService(this.StateManager, sessionProvider, instanceStore)); + this.client = new TaskHubClient(new FabricOrchestrationServiceClient(this.StateManager, sessionProvider, instanceStore)); this.testExecutor = new TestExecutor(this.client); } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 2bca15dd7..e1726eda3 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -31,7 +31,7 @@ public class FabricOrchestrationService : IOrchestrationService SessionsProvider orchestrationProvider; ActivitiesProvider activitiesProvider; - public FabricOrchestrationService(IReliableStateManager stateManager, IFabricOrchestrationServiceInstanceStore instanceStore) + public FabricOrchestrationService(IReliableStateManager stateManager, SessionsProvider orchestrationProvider, IFabricOrchestrationServiceInstanceStore instanceStore) { if (stateManager == null) { @@ -39,14 +39,14 @@ public FabricOrchestrationService(IReliableStateManager stateManager, IFabricOrc } this.stateManager = stateManager; + this.orchestrationProvider = orchestrationProvider; this.instanceStore = instanceStore; } public async Task StartAsync() { - var orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); this.activitiesProvider = new ActivitiesProvider(this.stateManager); - this.orchestrationProvider = new SessionsProvider(stateManager, orchestrations); + this.orchestrationProvider = new SessionsProvider(stateManager); await this.instanceStore.StartAsync(); await this.orchestrationProvider.StartAsync(); await this.activitiesProvider.StartAsync(); diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index a95c5949a..0f632d90e 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -25,10 +25,12 @@ public class FabricOrchestrationServiceClient : IOrchestrationServiceClient { IReliableStateManager stateManager; IFabricOrchestrationServiceInstanceStore instanceStore; + SessionsProvider orchestrationProvider; - public FabricOrchestrationServiceClient(IReliableStateManager stateManager, IFabricOrchestrationServiceInstanceStore instanceStore) + public FabricOrchestrationServiceClient(IReliableStateManager stateManager, SessionsProvider orchestrationProvider, IFabricOrchestrationServiceInstanceStore instanceStore) { this.stateManager = stateManager; + this.orchestrationProvider = orchestrationProvider; this.instanceStore = instanceStore; } @@ -47,19 +49,10 @@ public async Task CreateTaskOrchestrationAsync(TaskMessage creationMessage) public async Task SendTaskOrchestrationMessageAsync(TaskMessage message) { - var orchestrations = await this.GetOrAddOrchestrationsAsync(); - using (var txn = this.stateManager.CreateTransaction()) { - var sessionId = message.OrchestrationInstance.InstanceId; - - //Todo: This is the same code as SessionsProvider.AppendMessages, can perhaps reuse somehow? - Func newSessionFactory = (sid) => PersistentSession.CreateWithNewMessage(sid, message); - - await orchestrations.AddOrUpdateAsync(txn, sessionId, - addValueFactory: newSessionFactory, - updateValueFactory: (ses, oldValue) => oldValue.AppendMessage(message)); - + //Todo : Can this happen before the taskhub worker / orchestration service / sessionsprovider start? + await this.orchestrationProvider.AppendMessageAsync(txn, message); await txn.CommitAsync(); } } @@ -126,11 +119,6 @@ public async Task WaitForOrchestrationAsync(string instanceI return null; } - async Task> GetOrAddOrchestrationsAsync() - { - return await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); - } - void ThrowIfInstanceStoreNotConfigured() { if (this.instanceStore == null) diff --git a/src/DurableTask.ServiceFabric/PersistentSession.api.cs b/src/DurableTask.ServiceFabric/PersistentSession.api.cs index f5f0f6962..57445b674 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.api.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.api.cs @@ -89,6 +89,26 @@ public PersistentSession AppendMessageBatch(IEnumerable newMessages return Create(this.SessionId, this.SessionState.ToImmutableList(), messages, this.ScheduledMessages.ToImmutableList(), this.IsLocked); } + void UnlockSession(Builder builder) + { + builder.IsLocked = false; + builder.ShouldAddToQueue = builder.Messages.Any(); + } + + void LockSession(Builder builder) + { + builder.IsLocked = true; + builder.ShouldAddToQueue = false; + } + + void SetShouldAddToQueue(Builder builder) + { + if (!builder.IsLocked) + { + builder.ShouldAddToQueue = builder.Messages.Any(); + } + } + public static PersistentSession CreateWithNewMessage(string sessionId, TaskMessage newMessage) { var messages = ImmutableList.Empty.Add(ReceivableTaskMessage.Create(newMessage)); diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index a5b4e0d01..75cea3609 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -14,6 +14,7 @@ namespace DurableTask.ServiceFabric { using System; + using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -22,68 +23,67 @@ namespace DurableTask.ServiceFabric using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; - class SessionsProvider + public class SessionsProvider { IReliableStateManager stateManager; IReliableDictionary orchestrations; CancellationTokenSource cancellationTokenSource; readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId, null, null, null, false); + ConcurrentQueue inMemorySessions = new ConcurrentQueue(); - public SessionsProvider(IReliableStateManager stateManager, IReliableDictionary orchestrations) + public SessionsProvider(IReliableStateManager stateManager) { if (stateManager == null) { throw new ArgumentNullException(nameof(stateManager)); } - if (orchestrations == null) - { - throw new ArgumentNullException(nameof(orchestrations)); - } - this.stateManager = stateManager; - this.orchestrations = orchestrations; this.cancellationTokenSource = new CancellationTokenSource(); } - public Task StartAsync() + public async Task StartAsync() { - var nowait = Task.Run(async () => + this.orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); + + await PopulateInMemorySessions(); + + var nowait = ProcessScheduledMessages(); + } + + async Task ProcessScheduledMessages() + { + while (!this.cancellationTokenSource.IsCancellationRequested) { - while (!this.cancellationTokenSource.IsCancellationRequested) + var scheduledMessageSessions = new List(); + using (var txn = this.stateManager.CreateTransaction()) { - var scheduledMessageSessions = new List(); - using (var txn = this.stateManager.CreateTransaction()) + var enumerable = await this.orchestrations.CreateEnumerableAsync(txn, EnumerationMode.Unordered); + using (var enumerator = enumerable.GetAsyncEnumerator()) { - var enumerable = await this.orchestrations.CreateEnumerableAsync(txn, EnumerationMode.Unordered); - using (var enumerator = enumerable.GetAsyncEnumerator()) + while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) { - while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) + var entry = enumerator.Current; + if (entry.Value.ScheduledMessages.Any()) { - var entry = enumerator.Current; - if (entry.Value.ScheduledMessages.Any()) - { - scheduledMessageSessions.Add(entry.Key); - } + scheduledMessageSessions.Add(entry.Key); } } } + } - foreach (var sessionId in scheduledMessageSessions) + foreach (var sessionId in scheduledMessageSessions) + { + using (var txn = this.stateManager.CreateTransaction()) { - using (var txn = this.stateManager.CreateTransaction()) - { - await this.orchestrations.AddOrUpdateAsync(txn, sessionId, NewSessionFactory, (sId, oldValue) => oldValue.FireScheduledMessages()); - await txn.CommitAsync(); - } + await this.AddOrUpdateAsyncWrapper(txn, sessionId, NewSessionFactory, (sId, oldValue) => oldValue.FireScheduledMessages()); + await txn.CommitAsync(); } - - await Task.Delay(TimeSpan.FromMilliseconds(100)); } - }); - return Task.FromResult(null); + await Task.Delay(TimeSpan.FromMilliseconds(100)); + } } public void Stop() @@ -91,39 +91,19 @@ public void Stop() this.cancellationTokenSource.Cancel(); } - //Todo: This is O(N) and also a frequent operation, do we need to optimize this? public async Task AcceptSessionAsync(TimeSpan receiveTimeout) { Stopwatch timer = Stopwatch.StartNew(); while (timer.Elapsed < receiveTimeout && !this.cancellationTokenSource.IsCancellationRequested) { - string returnSessionId = null; - using (var tx = this.stateManager.CreateTransaction()) - { - var enumerable = await this.orchestrations.CreateEnumerableAsync(tx, EnumerationMode.Unordered); - using (var enumerator = enumerable.GetAsyncEnumerator()) - { - while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) - { - var entry = enumerator.Current; + string returnSessionId; - if (!entry.Value.Messages.Any()) - { - continue; - } - - returnSessionId = entry.Key; - break; - } - } - } - - if (returnSessionId != null) + if (this.inMemorySessions.TryDequeue(out returnSessionId)) { using (var txn = this.stateManager.CreateTransaction()) { //Todo: TryUpdate feels more natural here than AddOrUpdateAsync, however what do we do if it fails? - var result = await this.orchestrations.AddOrUpdateAsync(txn, returnSessionId, NewSessionFactory, (sId, oldValue) => oldValue.ReceiveMessages()); + var result = await this.AddOrUpdateAsyncWrapper(txn, returnSessionId, NewSessionFactory, (sId, oldValue) => oldValue.ReceiveMessages()); await txn.CommitAsync(); return result; } @@ -145,7 +125,7 @@ public async Task CompleteAndUpdateSession(ITransaction transaction, OrchestrationRuntimeState newSessionState, IList scheduledMessages) { - await this.orchestrations.AddOrUpdateAsync(transaction, sessionId, NewSessionFactory, + await this.AddOrUpdateAsyncWrapper(transaction, sessionId, NewSessionFactory, (sId, oldValue) => oldValue.CompleteMessages(newSessionState, scheduledMessages)); } @@ -153,7 +133,7 @@ public async Task AppendMessageAsync(ITransaction transaction, TaskMessage newMe { Func newSessionFactory = (sId) => PersistentSession.CreateWithNewMessage(sId, newMessage); - await this.orchestrations.AddOrUpdateAsync(transaction, newMessage.OrchestrationInstance.InstanceId, + await this.AddOrUpdateAsyncWrapper(transaction, newMessage.OrchestrationInstance.InstanceId, addValueFactory: newSessionFactory, updateValueFactory: (ses, oldValue) => oldValue.AppendMessage(newMessage)); } @@ -168,7 +148,7 @@ public async Task AppendMessageBatchAsync(ITransaction transaction, IEnumerable< Func newSessionFactory = (sId) => PersistentSession.CreateWithNewMessages(sId, groupMessages); - await this.orchestrations.AddOrUpdateAsync(transaction, group.Key, + await this.AddOrUpdateAsyncWrapper(transaction, group.Key, addValueFactory: newSessionFactory, updateValueFactory: (ses, oldValue) => oldValue.AppendMessageBatch(groupMessages)); } @@ -178,5 +158,36 @@ public async Task ReleaseSession(ITransaction transaction, string sessionId) { await this.orchestrations.TryRemoveAsync(transaction, sessionId); } + + async Task AddOrUpdateAsyncWrapper(ITransaction tx, string key, Func addValueFactory, Func updateValueFactory) + { + var newSession = await this.orchestrations.AddOrUpdateAsync(tx, key, addValueFactory, updateValueFactory); + + if (newSession.ShouldAddToQueue) + { + inMemorySessions.Enqueue(newSession.SessionId); + } + + return newSession; + } + + async Task PopulateInMemorySessions() + { + using (var txn = this.stateManager.CreateTransaction()) + { + var enumerable = await this.orchestrations.CreateEnumerableAsync(txn, EnumerationMode.Unordered); + using (var enumerator = enumerable.GetAsyncEnumerator()) + { + while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) + { + var entry = enumerator.Current; + if (entry.Value.Messages.Any()) + { + this.inMemorySessions.Enqueue(entry.Key); + } + } + } + } + } } } From 04abeb64f46bb3b7cefc2bc9db729daf77f361fd Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 063/210] Simple peek lock implementation for activities. Again there is no automatic lock expiry. (so there is no need for renewal) --- .../ActivitiesProvider.cs | 44 ++++++++++++++----- .../FabricOrchestrationService.cs | 5 ++- .../SessionsProvider.cs | 6 +-- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs index 11bcd2e22..00015c8ec 100644 --- a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs +++ b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs @@ -14,6 +14,7 @@ namespace DurableTask.ServiceFabric { using System; + using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Threading; @@ -26,7 +27,8 @@ class ActivitiesProvider readonly IReliableStateManager stateManager; readonly CancellationTokenSource cancellationTokenSource; - IReliableQueue activityQueue; + IReliableDictionary activityQueue; + ConcurrentQueue inMemoryQueue = new ConcurrentQueue(); public ActivitiesProvider(IReliableStateManager stateManager) { @@ -41,7 +43,7 @@ public ActivitiesProvider(IReliableStateManager stateManager) public async Task StartAsync() { - this.activityQueue = await this.stateManager.GetOrAddAsync>(Constants.ActivitiesQueueName); + this.activityQueue = await this.stateManager.GetOrAddAsync>(Constants.ActivitiesQueueName); } public void Stop() @@ -56,30 +58,50 @@ public async Task GetNextWorkItem(TimeSpan receiveTimeout) { using (var txn = this.stateManager.CreateTransaction()) { - var activityValue = await this.activityQueue.TryPeekAsync(txn, LockMode.Default); - if (activityValue.HasValue) + string activityId; + if (this.inMemoryQueue.TryDequeue(out activityId)) { - return activityValue.Value; + var activity = await this.activityQueue.TryGetValueAsync(txn, activityId); + if (activity.HasValue) + { + return activity.Value; + } + throw new Exception("Internal server error"); } } await Task.Delay(100, this.cancellationTokenSource.Token); + await PopulateInMemoryActivities(); } return null; } - // Currently the second parameter is ignored in implementation because it's expected that - // this method gets a call synchronously with the above method. When that changes, the implementation - // has to change accordingly. - public Task CompleteWorkItem(ITransaction transaction, TaskMessage message) + public Task CompleteWorkItem(ITransaction transaction, TaskActivityWorkItem workItem) { - return this.activityQueue.TryDequeueAsync(transaction); + return this.activityQueue.TryRemoveAsync(transaction, workItem.Id); } public async Task AppendBatch(ITransaction transaction, IList messages) { foreach (var message in messages) { - await this.activityQueue.EnqueueAsync(transaction, message); + var id = Guid.NewGuid().ToString(); + await this.activityQueue.AddAsync(transaction, id, message); + } + } + + async Task PopulateInMemoryActivities() + { + using (var txn = this.stateManager.CreateTransaction()) + { + var enumerable = await this.activityQueue.CreateEnumerableAsync(txn, EnumerationMode.Unordered); + using (var enumerator = enumerable.GetAsyncEnumerator()) + { + while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) + { + var entry = enumerator.Current; + this.inMemoryQueue.Enqueue(entry.Key); + } + } } } } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index e1726eda3..25ce9f46c 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -47,6 +47,7 @@ public async Task StartAsync() { this.activitiesProvider = new ActivitiesProvider(this.stateManager); this.orchestrationProvider = new SessionsProvider(stateManager); + await this.activitiesProvider.StartAsync(); await this.instanceStore.StartAsync(); await this.orchestrationProvider.StartAsync(); await this.activitiesProvider.StartAsync(); @@ -62,6 +63,7 @@ public async Task StopAsync(bool isForced) this.activitiesProvider.Stop(); this.orchestrationProvider.Stop(); await this.instanceStore.StopAsync(isForced); + this.activitiesProvider.Stop(); } public Task CreateAsync() @@ -231,8 +233,7 @@ public async Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workIte { using (var txn = this.stateManager.CreateTransaction()) { - await this.activitiesProvider.CompleteWorkItem(txn, workItem.TaskMessage); - var sessionId = workItem.TaskMessage.OrchestrationInstance.InstanceId; + await this.activitiesProvider.CompleteWorkItem(txn, workItem); await this.orchestrationProvider.AppendMessageAsync(txn, responseMessage); await txn.CommitAsync(); } diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 75cea3609..ac96954a5 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -25,11 +25,11 @@ namespace DurableTask.ServiceFabric public class SessionsProvider { - IReliableStateManager stateManager; - IReliableDictionary orchestrations; - CancellationTokenSource cancellationTokenSource; + readonly IReliableStateManager stateManager; + readonly CancellationTokenSource cancellationTokenSource; readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId, null, null, null, false); + IReliableDictionary orchestrations; ConcurrentQueue inMemorySessions = new ConcurrentQueue(); public SessionsProvider(IReliableStateManager stateManager) From 03f1d8add925bdfd79fbe42bf50981b5ca3890bf Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 064/210] reducing the time outs on tests and fixing a nullref caused by a race with StartAsync. --- Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs | 8 ++++---- src/DurableTask.ServiceFabric/SessionsProvider.cs | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs index 63a66fdad..36f266219 100644 --- a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs @@ -35,7 +35,7 @@ public void TestInitialize() [TestMethod] public async Task Orchestration_With_ScheduledTasks_Finishes() { - var result = await this.serviceClient.RunOrchestrationAsync(typeof(SimpleOrchestrationWithTasks).Name, null, TimeSpan.FromMinutes(5)); + var result = await this.serviceClient.RunOrchestrationAsync(typeof(SimpleOrchestrationWithTasks).Name, null, TimeSpan.FromMinutes(2)); Assert.AreEqual(OrchestrationStatus.Completed, result.OrchestrationStatus); Assert.AreEqual("\"Hello Gabbar\"", result.Output); @@ -45,7 +45,7 @@ public async Task Orchestration_With_ScheduledTasks_Finishes() public async Task Orchestration_With_Timer_Finishes_After_The_Wait_Time() { var waitTime = 37; - var result = await this.serviceClient.RunOrchestrationAsync(typeof(SimpleOrchestrationWithTimer).Name, waitTime, TimeSpan.FromMinutes(5)); + var result = await this.serviceClient.RunOrchestrationAsync(typeof(SimpleOrchestrationWithTimer).Name, waitTime, TimeSpan.FromMinutes(2)); Assert.AreEqual(OrchestrationStatus.Completed, result.OrchestrationStatus); Assert.AreEqual("\"Hello Gabbar\"", result.Output); @@ -61,7 +61,7 @@ public async Task GenerationBasicTest() GenerationBasicOrchestration.Result = 0; GenerationBasicTask.GenerationCount = 0; - var result = await this.serviceClient.RunOrchestrationAsync(typeof(GenerationBasicOrchestration).Name, 4, TimeSpan.FromMinutes(5)); + var result = await this.serviceClient.RunOrchestrationAsync(typeof(GenerationBasicOrchestration).Name, 4, TimeSpan.FromMinutes(2)); Assert.AreEqual(OrchestrationStatus.Completed, result.OrchestrationStatus); Assert.AreEqual(4, GenerationBasicOrchestration.Result, "Orchestration Result is wrong!!!"); @@ -70,7 +70,7 @@ public async Task GenerationBasicTest() [TestMethod] public async Task Orchestration_With_SubOrchestration_Finishes() { - var result = await this.serviceClient.RunOrchestrationAsync(typeof(SimpleOrchestrationWithSubOrchestration).Name, null, TimeSpan.FromMinutes(5)); + var result = await this.serviceClient.RunOrchestrationAsync(typeof(SimpleOrchestrationWithSubOrchestration).Name, null, TimeSpan.FromMinutes(2)); Assert.AreEqual(OrchestrationStatus.Completed, result.OrchestrationStatus); Assert.AreEqual($"\"TaskResult = Hello World , SubOrchestration1Result = Hello Gabbar, SubOrchestration2Result = Hello Gabbar\"", result.Output); diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index ac96954a5..88e6f7c54 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -161,6 +161,12 @@ public async Task ReleaseSession(ITransaction transaction, string sessionId) async Task AddOrUpdateAsyncWrapper(ITransaction tx, string key, Func addValueFactory, Func updateValueFactory) { + //Workaround to avoid client sending a new message before StartAsync on service is done + if (this.orchestrations == null) + { + this.orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); + } + var newSession = await this.orchestrations.AddOrUpdateAsync(tx, key, addValueFactory, updateValueFactory); if (newSession.ShouldAddToQueue) From 0f1dbac75dd02e7dc00c970c1f895ea129a37a2b Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 065/210] Something that works reliably (atleast in the context of a single node i.e., without node failures or process crashes) and performs comparable to service bus!!! (In fact, local SF cluster beats service bus roughly by 40%)!!! I still don't like the way code is written (in particular the sessions implementation) and the next task is to improve it or tweak it. (while keeping it reliable for single node). --- .../StressTests.cs | 2 +- .../ActivitiesProvider.cs | 53 +++++++++++++++---- .../FabricOrchestrationService.cs | 8 +-- .../PersistentSession.api.cs | 9 +++- .../SessionsProvider.cs | 39 ++++++++++---- 5 files changed, 86 insertions(+), 25 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.Test/StressTests.cs b/Test/DurableTask.ServiceFabric.Test/StressTests.cs index ccc5b59c8..7ff5c8ec8 100644 --- a/Test/DurableTask.ServiceFabric.Test/StressTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/StressTests.cs @@ -34,7 +34,7 @@ public async Task ExecuteStressTest() var driverConfig = new DriverOrchestrationData() { NumberOfIteration = 1, - NumberOfParallelTasks = 2, + NumberOfParallelTasks = 40, SubOrchestrationData = new TestOrchestrationData() { NumberOfParallelTasks = 10, diff --git a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs index 00015c8ec..57e2933c9 100644 --- a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs +++ b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs @@ -29,6 +29,9 @@ class ActivitiesProvider IReliableDictionary activityQueue; ConcurrentQueue inMemoryQueue = new ConcurrentQueue(); + HashSet lockTable = new HashSet(); + //bool newMessagesInStore; + //object syncLock = new object(); public ActivitiesProvider(IReliableStateManager stateManager) { @@ -44,6 +47,10 @@ public ActivitiesProvider(IReliableStateManager stateManager) public async Task StartAsync() { this.activityQueue = await this.stateManager.GetOrAddAsync>(Constants.ActivitiesQueueName); + //lock (syncLock) + //{ + // this.newMessagesInStore = true; + //} } public void Stop() @@ -75,31 +82,55 @@ public async Task GetNextWorkItem(TimeSpan receiveTimeout) return null; } - public Task CompleteWorkItem(ITransaction transaction, TaskActivityWorkItem workItem) + public async Task CompleteWorkItem(ITransaction transaction, TaskActivityWorkItem workItem) { - return this.activityQueue.TryRemoveAsync(transaction, workItem.Id); + await this.activityQueue.TryRemoveAsync(transaction, workItem.Id); } public async Task AppendBatch(ITransaction transaction, IList messages) { - foreach (var message in messages) + if (messages.Count > 0) { - var id = Guid.NewGuid().ToString(); - await this.activityQueue.AddAsync(transaction, id, message); + //lock (syncLock) + //{ + // this.newMessagesInStore = true; + //} + foreach (var message in messages) + { + var id = Guid.NewGuid().ToString(); + await this.activityQueue.AddAsync(transaction, id, message); + } } } async Task PopulateInMemoryActivities() { - using (var txn = this.stateManager.CreateTransaction()) + //var shouldFetchActivitiesInMemory = false; + //lock (syncLock) + //{ + // if (this.newMessagesInStore) + // { + // this.newMessagesInStore = false; + // shouldFetchActivitiesInMemory = true; + // } + //} + + //if (shouldFetchActivitiesInMemory) { - var enumerable = await this.activityQueue.CreateEnumerableAsync(txn, EnumerationMode.Unordered); - using (var enumerator = enumerable.GetAsyncEnumerator()) + using (var txn = this.stateManager.CreateTransaction()) { - while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) + var enumerable = await this.activityQueue.CreateEnumerableAsync(txn, EnumerationMode.Unordered); + using (var enumerator = enumerable.GetAsyncEnumerator()) { - var entry = enumerator.Current; - this.inMemoryQueue.Enqueue(entry.Key); + while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) + { + var activityId = enumerator.Current.Key; + if (!this.lockTable.Contains(activityId)) + { + this.inMemoryQueue.Enqueue(activityId); + this.lockTable.Add(activityId); + } + } } } } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 25ce9f46c..805cd2230 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -122,7 +122,7 @@ public int GetDelayInSecondsAfterOnFetchException(Exception exception) } public int TaskOrchestrationDispatcherCount => 1; - public int MaxConcurrentTaskOrchestrationWorkItems => 1; + public int MaxConcurrentTaskOrchestrationWorkItems => 100; // Note: Do not rely on cancellationToken parameter to this method because the top layer does not yet implement any cancellation. public async Task LockNextTaskOrchestrationWorkItemAsync(TimeSpan receiveTimeout, CancellationToken cancellationToken) @@ -190,6 +190,7 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( public Task AbandonTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkItem workItem) { + //Todo: Implement to unlock session return Task.FromResult(null); } @@ -210,7 +211,7 @@ public async Task ReleaseTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkIte } public int TaskActivityDispatcherCount => 1; - public int MaxConcurrentTaskActivityWorkItems => 1; + public int MaxConcurrentTaskActivityWorkItems => 100; // Note: Do not rely on cancellationToken parameter to this method because the top layer does not yet implement any cancellation. public async Task LockNextTaskActivityWorkItem(TimeSpan receiveTimeout, CancellationToken cancellationToken) @@ -241,10 +242,11 @@ public async Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workIte public Task AbandonTaskActivityWorkItemAsync(TaskActivityWorkItem workItem) { + //Todo: Implement to add back to in-memory queue return Task.FromResult(null); } - public bool ProcessWorkItemSynchronously => true; + public bool ProcessWorkItemSynchronously => false; public Task RenewTaskActivityWorkItemLockAsync(TaskActivityWorkItem workItem) { diff --git a/src/DurableTask.ServiceFabric/PersistentSession.api.cs b/src/DurableTask.ServiceFabric/PersistentSession.api.cs index 57445b674..df8bdb556 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.api.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.api.cs @@ -105,7 +105,14 @@ void SetShouldAddToQueue(Builder builder) { if (!builder.IsLocked) { - builder.ShouldAddToQueue = builder.Messages.Any(); + if (builder.ShouldAddToQueue) + { + builder.ShouldAddToQueue = false; + } + else + { + builder.ShouldAddToQueue = builder.Messages.Any(); + } } } diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 88e6f7c54..b3409d7e8 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -31,6 +31,7 @@ public class SessionsProvider readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId, null, null, null, false); IReliableDictionary orchestrations; ConcurrentQueue inMemorySessions = new ConcurrentQueue(); + private HashSet lockTable = new HashSet(); public SessionsProvider(IReliableStateManager stateManager) { @@ -98,7 +99,7 @@ public async Task AcceptSessionAsync(TimeSpan receiveTimeout) { string returnSessionId; - if (this.inMemorySessions.TryDequeue(out returnSessionId)) + if (this.TryDequeueSessionInMemory(out returnSessionId)) { using (var txn = this.stateManager.CreateTransaction()) { @@ -131,6 +132,12 @@ await this.AddOrUpdateAsyncWrapper(transaction, sessionId, NewSessionFactory, public async Task AppendMessageAsync(ITransaction transaction, TaskMessage newMessage) { + //Workaround to avoid client sending a new message before StartAsync on service is done + if (this.orchestrations == null) + { + this.orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); + } + Func newSessionFactory = (sId) => PersistentSession.CreateWithNewMessage(sId, newMessage); await this.AddOrUpdateAsyncWrapper(transaction, newMessage.OrchestrationInstance.InstanceId, @@ -161,17 +168,11 @@ public async Task ReleaseSession(ITransaction transaction, string sessionId) async Task AddOrUpdateAsyncWrapper(ITransaction tx, string key, Func addValueFactory, Func updateValueFactory) { - //Workaround to avoid client sending a new message before StartAsync on service is done - if (this.orchestrations == null) - { - this.orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); - } - var newSession = await this.orchestrations.AddOrUpdateAsync(tx, key, addValueFactory, updateValueFactory); if (newSession.ShouldAddToQueue) { - inMemorySessions.Enqueue(newSession.SessionId); + EnqueueSessionInMemory(newSession.SessionId); } return newSession; @@ -189,11 +190,31 @@ async Task PopulateInMemorySessions() var entry = enumerator.Current; if (entry.Value.Messages.Any()) { - this.inMemorySessions.Enqueue(entry.Key); + EnqueueSessionInMemory(entry.Key); } } } } } + + void EnqueueSessionInMemory(string sessionId) + { + if (!this.lockTable.Contains(sessionId)) + { + this.inMemorySessions.Enqueue(sessionId); + this.lockTable.Add(sessionId); + } + } + + bool TryDequeueSessionInMemory(out string returnSessionId) + { + if (this.inMemorySessions.TryDequeue(out returnSessionId)) + { + this.lockTable.Remove(returnSessionId); + return true; + } + + return false; + } } } From f8338d62ff092014775b4509e5dd40f909de0380 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 066/210] Simpler implementation for sessions (using similar approach as activity queue). It's still reliable at the scope of single node and performant as before. --- .../PersistentSession.api.cs | 27 ------------ .../SessionsProvider.cs | 41 ++++--------------- 2 files changed, 9 insertions(+), 59 deletions(-) diff --git a/src/DurableTask.ServiceFabric/PersistentSession.api.cs b/src/DurableTask.ServiceFabric/PersistentSession.api.cs index df8bdb556..f5f0f6962 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.api.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.api.cs @@ -89,33 +89,6 @@ public PersistentSession AppendMessageBatch(IEnumerable newMessages return Create(this.SessionId, this.SessionState.ToImmutableList(), messages, this.ScheduledMessages.ToImmutableList(), this.IsLocked); } - void UnlockSession(Builder builder) - { - builder.IsLocked = false; - builder.ShouldAddToQueue = builder.Messages.Any(); - } - - void LockSession(Builder builder) - { - builder.IsLocked = true; - builder.ShouldAddToQueue = false; - } - - void SetShouldAddToQueue(Builder builder) - { - if (!builder.IsLocked) - { - if (builder.ShouldAddToQueue) - { - builder.ShouldAddToQueue = false; - } - else - { - builder.ShouldAddToQueue = builder.Messages.Any(); - } - } - } - public static PersistentSession CreateWithNewMessage(string sessionId, TaskMessage newMessage) { var messages = ImmutableList.Empty.Add(ReceivableTaskMessage.Create(newMessage)); diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index b3409d7e8..47e9aae89 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -31,7 +31,6 @@ public class SessionsProvider readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId, null, null, null, false); IReliableDictionary orchestrations; ConcurrentQueue inMemorySessions = new ConcurrentQueue(); - private HashSet lockTable = new HashSet(); public SessionsProvider(IReliableStateManager stateManager) { @@ -47,9 +46,6 @@ public SessionsProvider(IReliableStateManager stateManager) public async Task StartAsync() { this.orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); - - await PopulateInMemorySessions(); - var nowait = ProcessScheduledMessages(); } @@ -78,7 +74,7 @@ async Task ProcessScheduledMessages() { using (var txn = this.stateManager.CreateTransaction()) { - await this.AddOrUpdateAsyncWrapper(txn, sessionId, NewSessionFactory, (sId, oldValue) => oldValue.FireScheduledMessages()); + await this.orchestrations.AddOrUpdateAsync(txn, sessionId, NewSessionFactory, (sId, oldValue) => oldValue.FireScheduledMessages()); await txn.CommitAsync(); } } @@ -99,18 +95,19 @@ public async Task AcceptSessionAsync(TimeSpan receiveTimeout) { string returnSessionId; - if (this.TryDequeueSessionInMemory(out returnSessionId)) + if (this.inMemorySessions.TryDequeue(out returnSessionId)) { using (var txn = this.stateManager.CreateTransaction()) { //Todo: TryUpdate feels more natural here than AddOrUpdateAsync, however what do we do if it fails? - var result = await this.AddOrUpdateAsyncWrapper(txn, returnSessionId, NewSessionFactory, (sId, oldValue) => oldValue.ReceiveMessages()); + var result = await this.orchestrations.AddOrUpdateAsync(txn, returnSessionId, NewSessionFactory, (sId, oldValue) => oldValue.ReceiveMessages()); await txn.CommitAsync(); return result; } } await Task.Delay(100, this.cancellationTokenSource.Token); + await PopulateInMemorySessions(); } return null; @@ -126,7 +123,7 @@ public async Task CompleteAndUpdateSession(ITransaction transaction, OrchestrationRuntimeState newSessionState, IList scheduledMessages) { - await this.AddOrUpdateAsyncWrapper(transaction, sessionId, NewSessionFactory, + await this.orchestrations.AddOrUpdateAsync(transaction, sessionId, NewSessionFactory, (sId, oldValue) => oldValue.CompleteMessages(newSessionState, scheduledMessages)); } @@ -140,7 +137,7 @@ public async Task AppendMessageAsync(ITransaction transaction, TaskMessage newMe Func newSessionFactory = (sId) => PersistentSession.CreateWithNewMessage(sId, newMessage); - await this.AddOrUpdateAsyncWrapper(transaction, newMessage.OrchestrationInstance.InstanceId, + await this.orchestrations.AddOrUpdateAsync(transaction, newMessage.OrchestrationInstance.InstanceId, addValueFactory: newSessionFactory, updateValueFactory: (ses, oldValue) => oldValue.AppendMessage(newMessage)); } @@ -155,7 +152,7 @@ public async Task AppendMessageBatchAsync(ITransaction transaction, IEnumerable< Func newSessionFactory = (sId) => PersistentSession.CreateWithNewMessages(sId, groupMessages); - await this.AddOrUpdateAsyncWrapper(transaction, group.Key, + await this.orchestrations.AddOrUpdateAsync(transaction, group.Key, addValueFactory: newSessionFactory, updateValueFactory: (ses, oldValue) => oldValue.AppendMessageBatch(groupMessages)); } @@ -188,33 +185,13 @@ async Task PopulateInMemorySessions() while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) { var entry = enumerator.Current; - if (entry.Value.Messages.Any()) + if (!entry.Value.IsLocked && entry.Value.Messages.Any()) { - EnqueueSessionInMemory(entry.Key); + this.inMemorySessions.Enqueue(entry.Key); } } } } } - - void EnqueueSessionInMemory(string sessionId) - { - if (!this.lockTable.Contains(sessionId)) - { - this.inMemorySessions.Enqueue(sessionId); - this.lockTable.Add(sessionId); - } - } - - bool TryDequeueSessionInMemory(out string returnSessionId) - { - if (this.inMemorySessions.TryDequeue(out returnSessionId)) - { - this.lockTable.Remove(returnSessionId); - return true; - } - - return false; - } } } From 0aabe26d02cfe305d908daf4aa0d9deb0a647ff9 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 30 Aug 2016 14:44:46 -0700 Subject: [PATCH 067/210] Cleaning up a couple of todo's after email thread with Andrew about immutable collections. ConvertAll is recommended way than SelectAll on immutable. --- src/DurableTask.ServiceFabric/PersistentSession.api.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DurableTask.ServiceFabric/PersistentSession.api.cs b/src/DurableTask.ServiceFabric/PersistentSession.api.cs index f5f0f6962..48561046d 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.api.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.api.cs @@ -37,7 +37,7 @@ public PersistentSession FireScheduledMessages() if (timerEvent == null) { //Should not happen with the current assumptions - throw new Exception("Internal server errors"); + throw new Exception("Internal server error."); } if (timerEvent.FireAt <= currentTime) From 25fbedeb6b69182f551362d4b064a6a00e28030f Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 12 Sep 2016 23:51:35 -0700 Subject: [PATCH 068/210] Changes to remove session row when the orchestration is complete. --- src/DurableTask.ServiceFabric/SessionsProvider.cs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 47e9aae89..8c4fa08c9 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -163,18 +163,6 @@ public async Task ReleaseSession(ITransaction transaction, string sessionId) await this.orchestrations.TryRemoveAsync(transaction, sessionId); } - async Task AddOrUpdateAsyncWrapper(ITransaction tx, string key, Func addValueFactory, Func updateValueFactory) - { - var newSession = await this.orchestrations.AddOrUpdateAsync(tx, key, addValueFactory, updateValueFactory); - - if (newSession.ShouldAddToQueue) - { - EnqueueSessionInMemory(newSession.SessionId); - } - - return newSession; - } - async Task PopulateInMemorySessions() { using (var txn = this.stateManager.CreateTransaction()) From 47686ccddf7f40bfb67a85e1c753e5d683a7426a Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 13 Sep 2016 00:00:57 -0700 Subject: [PATCH 069/210] Clearing some easy to-do's in code. --- .../FabricOrchestrationServiceClient.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index 0f632d90e..aad543c67 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -51,7 +51,6 @@ public async Task SendTaskOrchestrationMessageAsync(TaskMessage message) { using (var txn = this.stateManager.CreateTransaction()) { - //Todo : Can this happen before the taskhub worker / orchestration service / sessionsprovider start? await this.orchestrationProvider.AppendMessageAsync(txn, message); await txn.CommitAsync(); } From 49cc669ed1a281ecd5007261103f1c3bb915b654 Mon Sep 17 00:00:00 2001 From: pradeek Date: Wed, 14 Sep 2016 19:05:45 -0700 Subject: [PATCH 070/210] Event source and events within the provider. --- src/DurableTask.ServiceFabric/FabricOrchestrationService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 805cd2230..c147a3d81 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -122,7 +122,7 @@ public int GetDelayInSecondsAfterOnFetchException(Exception exception) } public int TaskOrchestrationDispatcherCount => 1; - public int MaxConcurrentTaskOrchestrationWorkItems => 100; + public int MaxConcurrentTaskOrchestrationWorkItems => 1000; // Note: Do not rely on cancellationToken parameter to this method because the top layer does not yet implement any cancellation. public async Task LockNextTaskOrchestrationWorkItemAsync(TimeSpan receiveTimeout, CancellationToken cancellationToken) @@ -211,7 +211,7 @@ public async Task ReleaseTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkIte } public int TaskActivityDispatcherCount => 1; - public int MaxConcurrentTaskActivityWorkItems => 100; + public int MaxConcurrentTaskActivityWorkItems => 10000; // Note: Do not rely on cancellationToken parameter to this method because the top layer does not yet implement any cancellation. public async Task LockNextTaskActivityWorkItem(TimeSpan receiveTimeout, CancellationToken cancellationToken) From 1a768ef9bc5b351904ad582f076cdd950a0006b2 Mon Sep 17 00:00:00 2001 From: pradeek Date: Thu, 15 Sep 2016 15:18:29 -0700 Subject: [PATCH 071/210] Fixing an issue observed while testing node failures. --- .../ActivitiesProvider.cs | 3 +++ .../SessionsProvider.cs | 17 ++++++++++------- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs index 57e2933c9..2492cd52b 100644 --- a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs +++ b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs @@ -22,6 +22,7 @@ namespace DurableTask.ServiceFabric using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; + //Todo: Refactor common components of this class and SessionsProvider class ActivitiesProvider { readonly IReliableStateManager stateManager; @@ -85,6 +86,7 @@ public async Task GetNextWorkItem(TimeSpan receiveTimeout) public async Task CompleteWorkItem(ITransaction transaction, TaskActivityWorkItem workItem) { await this.activityQueue.TryRemoveAsync(transaction, workItem.Id); + this.lockTable.Remove(workItem.Id); } public async Task AppendBatch(ITransaction transaction, IList messages) @@ -116,6 +118,7 @@ async Task PopulateInMemoryActivities() //} //if (shouldFetchActivitiesInMemory) + if (!this.cancellationTokenSource.IsCancellationRequested) { using (var txn = this.stateManager.CreateTransaction()) { diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 8c4fa08c9..1ef02cade 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -165,17 +165,20 @@ public async Task ReleaseSession(ITransaction transaction, string sessionId) async Task PopulateInMemorySessions() { - using (var txn = this.stateManager.CreateTransaction()) + if (!this.cancellationTokenSource.IsCancellationRequested) { - var enumerable = await this.orchestrations.CreateEnumerableAsync(txn, EnumerationMode.Unordered); - using (var enumerator = enumerable.GetAsyncEnumerator()) + using (var txn = this.stateManager.CreateTransaction()) { - while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) + var enumerable = await this.orchestrations.CreateEnumerableAsync(txn, EnumerationMode.Unordered); + using (var enumerator = enumerable.GetAsyncEnumerator()) { - var entry = enumerator.Current; - if (!entry.Value.IsLocked && entry.Value.Messages.Any()) + while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) { - this.inMemorySessions.Enqueue(entry.Key); + var entry = enumerator.Current; + if (!entry.Value.IsLocked && entry.Value.Messages.Any()) + { + this.inMemorySessions.Enqueue(entry.Key); + } } } } From 31894353ea00fcaeffa07175a81321b5d3d942e9 Mon Sep 17 00:00:00 2001 From: pradeek Date: Thu, 15 Sep 2016 16:36:41 -0700 Subject: [PATCH 072/210] Fixing the regression (tests failed and now they are back to passing). --- src/DurableTask.ServiceFabric/ActivitiesProvider.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs index 2492cd52b..8d3709017 100644 --- a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs +++ b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs @@ -30,7 +30,7 @@ class ActivitiesProvider IReliableDictionary activityQueue; ConcurrentQueue inMemoryQueue = new ConcurrentQueue(); - HashSet lockTable = new HashSet(); + ConcurrentDictionary lockTable = new ConcurrentDictionary(); //bool newMessagesInStore; //object syncLock = new object(); @@ -86,7 +86,8 @@ public async Task GetNextWorkItem(TimeSpan receiveTimeout) public async Task CompleteWorkItem(ITransaction transaction, TaskActivityWorkItem workItem) { await this.activityQueue.TryRemoveAsync(transaction, workItem.Id); - this.lockTable.Remove(workItem.Id); + bool ignored; + this.lockTable.TryRemove(workItem.Id, out ignored); } public async Task AppendBatch(ITransaction transaction, IList messages) @@ -128,10 +129,10 @@ async Task PopulateInMemoryActivities() while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) { var activityId = enumerator.Current.Key; - if (!this.lockTable.Contains(activityId)) + if (!this.lockTable.ContainsKey(activityId)) { this.inMemoryQueue.Enqueue(activityId); - this.lockTable.Add(activityId); + this.lockTable.TryAdd(activityId, true); } } } From 3cd5350b49e694f91a4ad0d90df68d998b983712 Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 16 Sep 2016 00:42:30 -0700 Subject: [PATCH 073/210] Commented code that's required but causing problems because of transaction semantics in SF. Added a todo for later. --- src/DurableTask.ServiceFabric/ActivitiesProvider.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs index 8d3709017..64a97d6e5 100644 --- a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs +++ b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs @@ -86,8 +86,9 @@ public async Task GetNextWorkItem(TimeSpan receiveTimeout) public async Task CompleteWorkItem(ITransaction transaction, TaskActivityWorkItem workItem) { await this.activityQueue.TryRemoveAsync(transaction, workItem.Id); - bool ignored; - this.lockTable.TryRemove(workItem.Id, out ignored); + //Todo: Need to cleanup the lock table only after the transaction commit... + //bool ignored; + //this.lockTable.TryRemove(workItem.Id, out ignored); } public async Task AppendBatch(ITransaction transaction, IList messages) From 71a2317439acb68ffdbed0d62430474d744685e5 Mon Sep 17 00:00:00 2001 From: pradeek Date: Thu, 15 Sep 2016 16:36:41 -0700 Subject: [PATCH 074/210] Ugly serialization fix to identify other issues - I am comminting this in a different branch and I will fix it in a proper way. --- .../DurableTask.ServiceFabric.csproj | 3 + .../PersistentSession.generated.cs | 371 ++++++++++++++++++ 2 files changed, 374 insertions(+) create mode 100644 src/DurableTask.ServiceFabric/PersistentSession.generated.cs diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 28197568e..09eccea21 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -86,6 +86,9 @@ MSBuild:GenerateCodeFromAttributes + + PersistentSession.cs + diff --git a/src/DurableTask.ServiceFabric/PersistentSession.generated.cs b/src/DurableTask.ServiceFabric/PersistentSession.generated.cs new file mode 100644 index 000000000..b703940dd --- /dev/null +++ b/src/DurableTask.ServiceFabric/PersistentSession.generated.cs @@ -0,0 +1,371 @@ +// ------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +// ------------------------------------------------------------------------------ + +using System; +using System.Collections.Immutable; +using System.Runtime.Serialization; +using DurableTask.History; +using ImmutableObjectGraph.Generation; + +namespace DurableTask.ServiceFabric +{ + partial class PersistentSession + { + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + private static readonly PersistentSession DefaultInstance = GetDefaultTemplate(); + private static int lastIdentityProduced; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + private readonly uint identity; + [System.ObsoleteAttribute("This constructor for use with deserializers only. Use the static Create factory method instead.")] + public PersistentSession(System.String SessionId, System.Collections.Immutable.ImmutableList SessionState, System.Collections.Immutable.ImmutableList Messages, System.Collections.Immutable.ImmutableList ScheduledMessages, System.Boolean IsLocked) : this(NewIdentity(), sessionId: SessionId, sessionState: SessionState, messages: Messages, scheduledMessages: ScheduledMessages, isLocked: IsLocked, skipValidation: false) + { + } + + PersistentSession(uint identity, System.String sessionId, System.Collections.Immutable.ImmutableList sessionState, System.Collections.Immutable.ImmutableList messages, System.Collections.Immutable.ImmutableList scheduledMessages, System.Boolean isLocked, bool skipValidation) + { + this.identity = identity; + this.sessionId = sessionId; + this.sessionState = sessionState; + this.messages = messages; + this.scheduledMessages = scheduledMessages; + this.isLocked = isLocked; + if (!skipValidation) + { + this.Validate(); + } + } + + public bool IsLocked => this.isLocked; + public ImmutableList Messages => this.messages; + public ImmutableList ScheduledMessages => this.scheduledMessages; + public string SessionId => this.sessionId; + public ImmutableList SessionState => this.sessionState; + internal uint Identity => this.identity; + public static PersistentSession Create(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional)) + { + var identity = ImmutableObjectGraph.Optional.For(NewIdentity()); + return DefaultInstance.WithFactory(sessionId: ImmutableObjectGraph.Optional.For(sessionId.GetValueOrDefault(DefaultInstance.SessionId)), sessionState: ImmutableObjectGraph.Optional.For(sessionState.GetValueOrDefault(DefaultInstance.SessionState)), messages: ImmutableObjectGraph.Optional.For(messages.GetValueOrDefault(DefaultInstance.Messages)), scheduledMessages: ImmutableObjectGraph.Optional.For(scheduledMessages.GetValueOrDefault(DefaultInstance.ScheduledMessages)), isLocked: ImmutableObjectGraph.Optional.For(isLocked.GetValueOrDefault(DefaultInstance.IsLocked)), identity: identity); + } + + public static Builder CreateBuilder() => new Builder(DefaultInstance); + public Builder ToBuilder() => new Builder(this); + public PersistentSession With(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional)) + { + return (PersistentSession)this.WithCore(sessionId: sessionId, sessionState: sessionState, messages: messages, scheduledMessages: scheduledMessages, isLocked: isLocked); + } + + static partial void CreateDefaultTemplate(ref Template template); + private static PersistentSession GetDefaultTemplate() + { + var template = new Template(); + CreateDefaultTemplate(ref template); + return new PersistentSession(default(uint), template.SessionId, template.SessionState, template.Messages, template.ScheduledMessages, template.IsLocked, skipValidation: true); + } + + static uint NewIdentity() + { + return (uint)System.Threading.Interlocked.Increment(ref lastIdentityProduced); + } + + partial void Validate(); + PersistentSession WithCore(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional)) + { + return this.WithFactory(sessionId: sessionId, sessionState: sessionState, messages: messages, scheduledMessages: scheduledMessages, isLocked: isLocked, identity: ImmutableObjectGraph.Optional.For(this.Identity)); + } + + private PersistentSession WithFactory(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional identity = default(ImmutableObjectGraph.Optional)) + { + if ((identity.IsDefined && identity.Value != this.Identity) || (sessionId.IsDefined && sessionId.Value != this.SessionId) || (sessionState.IsDefined && sessionState.Value != this.SessionState) || (messages.IsDefined && messages.Value != this.Messages) || (scheduledMessages.IsDefined && scheduledMessages.Value != this.ScheduledMessages) || (isLocked.IsDefined && isLocked.Value != this.IsLocked)) + { + return new PersistentSession(identity: identity.GetValueOrDefault(this.Identity), sessionId: sessionId.GetValueOrDefault(this.SessionId), sessionState: sessionState.GetValueOrDefault(this.SessionState), messages: messages.GetValueOrDefault(this.Messages), scheduledMessages: scheduledMessages.GetValueOrDefault(this.ScheduledMessages), isLocked: isLocked.GetValueOrDefault(this.IsLocked), skipValidation: false); + } + else + { + return this; + } + } + + public partial class Builder : System.ComponentModel.INotifyPropertyChanged + { + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected System.Boolean isLocked; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected System.Collections.Immutable.ImmutableList messages; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected System.Collections.Immutable.ImmutableList scheduledMessages; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected System.String sessionId; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected System.Collections.Immutable.ImmutableList sessionState; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + private PersistentSession immutable; + internal Builder(PersistentSession immutable) + { + this.immutable = immutable; + this.sessionId = immutable.sessionId; + this.sessionState = immutable.sessionState; + this.messages = immutable.messages; + this.scheduledMessages = immutable.scheduledMessages; + this.isLocked = immutable.isLocked; + } + + public System.Boolean IsLocked + { + get + { + return this.isLocked; + } + + set + { + if (this.isLocked != value) + { + this.isLocked = value; + this.OnPropertyChanged(); + } + } + } + + public System.Collections.Immutable.ImmutableList Messages + { + get + { + return this.messages; + } + + set + { + if (this.messages != value) + { + this.messages = value; + this.OnPropertyChanged(); + } + } + } + + public System.Collections.Immutable.ImmutableList ScheduledMessages + { + get + { + return this.scheduledMessages; + } + + set + { + if (this.scheduledMessages != value) + { + this.scheduledMessages = value; + this.OnPropertyChanged(); + } + } + } + + public System.String SessionId + { + get + { + return this.sessionId; + } + + set + { + if (this.sessionId != value) + { + this.sessionId = value; + this.OnPropertyChanged(); + } + } + } + + public System.Collections.Immutable.ImmutableList SessionState + { + get + { + return this.sessionState; + } + + set + { + if (this.sessionState != value) + { + this.sessionState = value; + this.OnPropertyChanged(); + } + } + } + + public PersistentSession ToImmutable() + { + return this.immutable = this.immutable.With(ImmutableObjectGraph.Optional.For(this.SessionId), ImmutableObjectGraph.Optional.For(this.SessionState), ImmutableObjectGraph.Optional.For(this.Messages), ImmutableObjectGraph.Optional.For(this.ScheduledMessages), ImmutableObjectGraph.Optional.For(this.IsLocked)); + } + + protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberNameAttribute] string propertyName = "") + { + this.PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + } + +#pragma warning disable 649 // field initialization is optional in user code + + private struct Template + { + internal System.Boolean IsLocked; + internal System.Collections.Immutable.ImmutableList Messages; + internal System.Collections.Immutable.ImmutableList ScheduledMessages; + internal System.String SessionId; + internal System.Collections.Immutable.ImmutableList SessionState; + } +#pragma warning restore 649 + } +} + +namespace DurableTask.ServiceFabric +{ + partial class ReceivableTaskMessage + { + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + private static readonly ReceivableTaskMessage DefaultInstance = GetDefaultTemplate(); + private static int lastIdentityProduced; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + private readonly uint identity; + [System.ObsoleteAttribute("This constructor for use with deserializers only. Use the static Create factory method instead.")] + public ReceivableTaskMessage(DurableTask.TaskMessage TaskMessage, System.Boolean IsReceived) : this(NewIdentity(), taskMessage: TaskMessage, isReceived: IsReceived, skipValidation: false) + { + } + + ReceivableTaskMessage(uint identity, DurableTask.TaskMessage taskMessage, System.Boolean isReceived, bool skipValidation) + { + this.identity = identity; + this.taskMessage = taskMessage; + this.isReceived = isReceived; + if (!skipValidation) + { + this.Validate(); + } + } + + public bool IsReceived => this.isReceived; + public TaskMessage TaskMessage => this.taskMessage; + internal uint Identity => this.identity; + public static ReceivableTaskMessage Create(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional)) + { + var identity = ImmutableObjectGraph.Optional.For(NewIdentity()); + return DefaultInstance.WithFactory(taskMessage: ImmutableObjectGraph.Optional.For(taskMessage.GetValueOrDefault(DefaultInstance.TaskMessage)), isReceived: ImmutableObjectGraph.Optional.For(isReceived.GetValueOrDefault(DefaultInstance.IsReceived)), identity: identity); + } + + public static Builder CreateBuilder() => new Builder(DefaultInstance); + public Builder ToBuilder() => new Builder(this); + public ReceivableTaskMessage With(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional)) + { + return (ReceivableTaskMessage)this.WithCore(taskMessage: taskMessage, isReceived: isReceived); + } + + static partial void CreateDefaultTemplate(ref Template template); + private static ReceivableTaskMessage GetDefaultTemplate() + { + var template = new Template(); + CreateDefaultTemplate(ref template); + return new ReceivableTaskMessage(default(uint), template.TaskMessage, template.IsReceived, skipValidation: true); + } + + static uint NewIdentity() + { + return (uint)System.Threading.Interlocked.Increment(ref lastIdentityProduced); + } + + partial void Validate(); + ReceivableTaskMessage WithCore(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional)) + { + return this.WithFactory(taskMessage: taskMessage, isReceived: isReceived, identity: ImmutableObjectGraph.Optional.For(this.Identity)); + } + + private ReceivableTaskMessage WithFactory(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional identity = default(ImmutableObjectGraph.Optional)) + { + if ((identity.IsDefined && identity.Value != this.Identity) || (taskMessage.IsDefined && taskMessage.Value != this.TaskMessage) || (isReceived.IsDefined && isReceived.Value != this.IsReceived)) + { + return new ReceivableTaskMessage(identity: identity.GetValueOrDefault(this.Identity), taskMessage: taskMessage.GetValueOrDefault(this.TaskMessage), isReceived: isReceived.GetValueOrDefault(this.IsReceived), skipValidation: false); + } + else + { + return this; + } + } + + public partial class Builder : System.ComponentModel.INotifyPropertyChanged + { + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected System.Boolean isReceived; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + protected DurableTask.TaskMessage taskMessage; + [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] + private ReceivableTaskMessage immutable; + internal Builder(ReceivableTaskMessage immutable) + { + this.immutable = immutable; + this.taskMessage = immutable.taskMessage; + this.isReceived = immutable.isReceived; + } + + public System.Boolean IsReceived + { + get + { + return this.isReceived; + } + + set + { + if (this.isReceived != value) + { + this.isReceived = value; + this.OnPropertyChanged(); + } + } + } + + public DurableTask.TaskMessage TaskMessage + { + get + { + return this.taskMessage; + } + + set + { + if (this.taskMessage != value) + { + this.taskMessage = value; + this.OnPropertyChanged(); + } + } + } + + public ReceivableTaskMessage ToImmutable() + { + return this.immutable = this.immutable.With(ImmutableObjectGraph.Optional.For(this.TaskMessage), ImmutableObjectGraph.Optional.For(this.IsReceived)); + } + + protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberNameAttribute] string propertyName = "") + { + this.PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + } + +#pragma warning disable 649 // field initialization is optional in user code + + private struct Template + { + internal System.Boolean IsReceived; + internal DurableTask.TaskMessage TaskMessage; + } +#pragma warning restore 649 + } +} \ No newline at end of file From 52ee83576acef2714036c112510882a524f748b8 Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 16 Sep 2016 10:35:46 -0700 Subject: [PATCH 075/210] May not have optimizations for memory but something that might work... --- .../DurableTask.ServiceFabric.csproj | 3 - .../PersistentSession.cs | 2 +- .../PersistentSession.generated.cs | 371 ------------------ 3 files changed, 1 insertion(+), 375 deletions(-) delete mode 100644 src/DurableTask.ServiceFabric/PersistentSession.generated.cs diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 09eccea21..28197568e 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -86,9 +86,6 @@ MSBuild:GenerateCodeFromAttributes - - PersistentSession.cs - diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index ca511e67a..d3c2fd6f7 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -41,7 +41,7 @@ public sealed partial class PersistentSession [DataMember] public IEnumerable ScheduledMessages { get; private set; } - public bool IsLocked { get; } + public bool IsLocked { get; private set; } [OnDeserialized] private void OnDeserialized(StreamingContext context) diff --git a/src/DurableTask.ServiceFabric/PersistentSession.generated.cs b/src/DurableTask.ServiceFabric/PersistentSession.generated.cs deleted file mode 100644 index b703940dd..000000000 --- a/src/DurableTask.ServiceFabric/PersistentSession.generated.cs +++ /dev/null @@ -1,371 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// ------------------------------------------------------------------------------ - -using System; -using System.Collections.Immutable; -using System.Runtime.Serialization; -using DurableTask.History; -using ImmutableObjectGraph.Generation; - -namespace DurableTask.ServiceFabric -{ - partial class PersistentSession - { - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - private static readonly PersistentSession DefaultInstance = GetDefaultTemplate(); - private static int lastIdentityProduced; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - private readonly uint identity; - [System.ObsoleteAttribute("This constructor for use with deserializers only. Use the static Create factory method instead.")] - public PersistentSession(System.String SessionId, System.Collections.Immutable.ImmutableList SessionState, System.Collections.Immutable.ImmutableList Messages, System.Collections.Immutable.ImmutableList ScheduledMessages, System.Boolean IsLocked) : this(NewIdentity(), sessionId: SessionId, sessionState: SessionState, messages: Messages, scheduledMessages: ScheduledMessages, isLocked: IsLocked, skipValidation: false) - { - } - - PersistentSession(uint identity, System.String sessionId, System.Collections.Immutable.ImmutableList sessionState, System.Collections.Immutable.ImmutableList messages, System.Collections.Immutable.ImmutableList scheduledMessages, System.Boolean isLocked, bool skipValidation) - { - this.identity = identity; - this.sessionId = sessionId; - this.sessionState = sessionState; - this.messages = messages; - this.scheduledMessages = scheduledMessages; - this.isLocked = isLocked; - if (!skipValidation) - { - this.Validate(); - } - } - - public bool IsLocked => this.isLocked; - public ImmutableList Messages => this.messages; - public ImmutableList ScheduledMessages => this.scheduledMessages; - public string SessionId => this.sessionId; - public ImmutableList SessionState => this.sessionState; - internal uint Identity => this.identity; - public static PersistentSession Create(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional)) - { - var identity = ImmutableObjectGraph.Optional.For(NewIdentity()); - return DefaultInstance.WithFactory(sessionId: ImmutableObjectGraph.Optional.For(sessionId.GetValueOrDefault(DefaultInstance.SessionId)), sessionState: ImmutableObjectGraph.Optional.For(sessionState.GetValueOrDefault(DefaultInstance.SessionState)), messages: ImmutableObjectGraph.Optional.For(messages.GetValueOrDefault(DefaultInstance.Messages)), scheduledMessages: ImmutableObjectGraph.Optional.For(scheduledMessages.GetValueOrDefault(DefaultInstance.ScheduledMessages)), isLocked: ImmutableObjectGraph.Optional.For(isLocked.GetValueOrDefault(DefaultInstance.IsLocked)), identity: identity); - } - - public static Builder CreateBuilder() => new Builder(DefaultInstance); - public Builder ToBuilder() => new Builder(this); - public PersistentSession With(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional)) - { - return (PersistentSession)this.WithCore(sessionId: sessionId, sessionState: sessionState, messages: messages, scheduledMessages: scheduledMessages, isLocked: isLocked); - } - - static partial void CreateDefaultTemplate(ref Template template); - private static PersistentSession GetDefaultTemplate() - { - var template = new Template(); - CreateDefaultTemplate(ref template); - return new PersistentSession(default(uint), template.SessionId, template.SessionState, template.Messages, template.ScheduledMessages, template.IsLocked, skipValidation: true); - } - - static uint NewIdentity() - { - return (uint)System.Threading.Interlocked.Increment(ref lastIdentityProduced); - } - - partial void Validate(); - PersistentSession WithCore(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional)) - { - return this.WithFactory(sessionId: sessionId, sessionState: sessionState, messages: messages, scheduledMessages: scheduledMessages, isLocked: isLocked, identity: ImmutableObjectGraph.Optional.For(this.Identity)); - } - - private PersistentSession WithFactory(ImmutableObjectGraph.Optional sessionId = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional> sessionState = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> messages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional> scheduledMessages = default(ImmutableObjectGraph.Optional>), ImmutableObjectGraph.Optional isLocked = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional identity = default(ImmutableObjectGraph.Optional)) - { - if ((identity.IsDefined && identity.Value != this.Identity) || (sessionId.IsDefined && sessionId.Value != this.SessionId) || (sessionState.IsDefined && sessionState.Value != this.SessionState) || (messages.IsDefined && messages.Value != this.Messages) || (scheduledMessages.IsDefined && scheduledMessages.Value != this.ScheduledMessages) || (isLocked.IsDefined && isLocked.Value != this.IsLocked)) - { - return new PersistentSession(identity: identity.GetValueOrDefault(this.Identity), sessionId: sessionId.GetValueOrDefault(this.SessionId), sessionState: sessionState.GetValueOrDefault(this.SessionState), messages: messages.GetValueOrDefault(this.Messages), scheduledMessages: scheduledMessages.GetValueOrDefault(this.ScheduledMessages), isLocked: isLocked.GetValueOrDefault(this.IsLocked), skipValidation: false); - } - else - { - return this; - } - } - - public partial class Builder : System.ComponentModel.INotifyPropertyChanged - { - public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected System.Boolean isLocked; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected System.Collections.Immutable.ImmutableList messages; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected System.Collections.Immutable.ImmutableList scheduledMessages; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected System.String sessionId; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected System.Collections.Immutable.ImmutableList sessionState; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - private PersistentSession immutable; - internal Builder(PersistentSession immutable) - { - this.immutable = immutable; - this.sessionId = immutable.sessionId; - this.sessionState = immutable.sessionState; - this.messages = immutable.messages; - this.scheduledMessages = immutable.scheduledMessages; - this.isLocked = immutable.isLocked; - } - - public System.Boolean IsLocked - { - get - { - return this.isLocked; - } - - set - { - if (this.isLocked != value) - { - this.isLocked = value; - this.OnPropertyChanged(); - } - } - } - - public System.Collections.Immutable.ImmutableList Messages - { - get - { - return this.messages; - } - - set - { - if (this.messages != value) - { - this.messages = value; - this.OnPropertyChanged(); - } - } - } - - public System.Collections.Immutable.ImmutableList ScheduledMessages - { - get - { - return this.scheduledMessages; - } - - set - { - if (this.scheduledMessages != value) - { - this.scheduledMessages = value; - this.OnPropertyChanged(); - } - } - } - - public System.String SessionId - { - get - { - return this.sessionId; - } - - set - { - if (this.sessionId != value) - { - this.sessionId = value; - this.OnPropertyChanged(); - } - } - } - - public System.Collections.Immutable.ImmutableList SessionState - { - get - { - return this.sessionState; - } - - set - { - if (this.sessionState != value) - { - this.sessionState = value; - this.OnPropertyChanged(); - } - } - } - - public PersistentSession ToImmutable() - { - return this.immutable = this.immutable.With(ImmutableObjectGraph.Optional.For(this.SessionId), ImmutableObjectGraph.Optional.For(this.SessionState), ImmutableObjectGraph.Optional.For(this.Messages), ImmutableObjectGraph.Optional.For(this.ScheduledMessages), ImmutableObjectGraph.Optional.For(this.IsLocked)); - } - - protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberNameAttribute] string propertyName = "") - { - this.PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); - } - } - -#pragma warning disable 649 // field initialization is optional in user code - - private struct Template - { - internal System.Boolean IsLocked; - internal System.Collections.Immutable.ImmutableList Messages; - internal System.Collections.Immutable.ImmutableList ScheduledMessages; - internal System.String SessionId; - internal System.Collections.Immutable.ImmutableList SessionState; - } -#pragma warning restore 649 - } -} - -namespace DurableTask.ServiceFabric -{ - partial class ReceivableTaskMessage - { - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - private static readonly ReceivableTaskMessage DefaultInstance = GetDefaultTemplate(); - private static int lastIdentityProduced; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - private readonly uint identity; - [System.ObsoleteAttribute("This constructor for use with deserializers only. Use the static Create factory method instead.")] - public ReceivableTaskMessage(DurableTask.TaskMessage TaskMessage, System.Boolean IsReceived) : this(NewIdentity(), taskMessage: TaskMessage, isReceived: IsReceived, skipValidation: false) - { - } - - ReceivableTaskMessage(uint identity, DurableTask.TaskMessage taskMessage, System.Boolean isReceived, bool skipValidation) - { - this.identity = identity; - this.taskMessage = taskMessage; - this.isReceived = isReceived; - if (!skipValidation) - { - this.Validate(); - } - } - - public bool IsReceived => this.isReceived; - public TaskMessage TaskMessage => this.taskMessage; - internal uint Identity => this.identity; - public static ReceivableTaskMessage Create(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional)) - { - var identity = ImmutableObjectGraph.Optional.For(NewIdentity()); - return DefaultInstance.WithFactory(taskMessage: ImmutableObjectGraph.Optional.For(taskMessage.GetValueOrDefault(DefaultInstance.TaskMessage)), isReceived: ImmutableObjectGraph.Optional.For(isReceived.GetValueOrDefault(DefaultInstance.IsReceived)), identity: identity); - } - - public static Builder CreateBuilder() => new Builder(DefaultInstance); - public Builder ToBuilder() => new Builder(this); - public ReceivableTaskMessage With(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional)) - { - return (ReceivableTaskMessage)this.WithCore(taskMessage: taskMessage, isReceived: isReceived); - } - - static partial void CreateDefaultTemplate(ref Template template); - private static ReceivableTaskMessage GetDefaultTemplate() - { - var template = new Template(); - CreateDefaultTemplate(ref template); - return new ReceivableTaskMessage(default(uint), template.TaskMessage, template.IsReceived, skipValidation: true); - } - - static uint NewIdentity() - { - return (uint)System.Threading.Interlocked.Increment(ref lastIdentityProduced); - } - - partial void Validate(); - ReceivableTaskMessage WithCore(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional)) - { - return this.WithFactory(taskMessage: taskMessage, isReceived: isReceived, identity: ImmutableObjectGraph.Optional.For(this.Identity)); - } - - private ReceivableTaskMessage WithFactory(ImmutableObjectGraph.Optional taskMessage = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional isReceived = default(ImmutableObjectGraph.Optional), ImmutableObjectGraph.Optional identity = default(ImmutableObjectGraph.Optional)) - { - if ((identity.IsDefined && identity.Value != this.Identity) || (taskMessage.IsDefined && taskMessage.Value != this.TaskMessage) || (isReceived.IsDefined && isReceived.Value != this.IsReceived)) - { - return new ReceivableTaskMessage(identity: identity.GetValueOrDefault(this.Identity), taskMessage: taskMessage.GetValueOrDefault(this.TaskMessage), isReceived: isReceived.GetValueOrDefault(this.IsReceived), skipValidation: false); - } - else - { - return this; - } - } - - public partial class Builder : System.ComponentModel.INotifyPropertyChanged - { - public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected System.Boolean isReceived; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - protected DurableTask.TaskMessage taskMessage; - [System.Diagnostics.DebuggerBrowsableAttribute(System.Diagnostics.DebuggerBrowsableState.Never)] - private ReceivableTaskMessage immutable; - internal Builder(ReceivableTaskMessage immutable) - { - this.immutable = immutable; - this.taskMessage = immutable.taskMessage; - this.isReceived = immutable.isReceived; - } - - public System.Boolean IsReceived - { - get - { - return this.isReceived; - } - - set - { - if (this.isReceived != value) - { - this.isReceived = value; - this.OnPropertyChanged(); - } - } - } - - public DurableTask.TaskMessage TaskMessage - { - get - { - return this.taskMessage; - } - - set - { - if (this.taskMessage != value) - { - this.taskMessage = value; - this.OnPropertyChanged(); - } - } - } - - public ReceivableTaskMessage ToImmutable() - { - return this.immutable = this.immutable.With(ImmutableObjectGraph.Optional.For(this.TaskMessage), ImmutableObjectGraph.Optional.For(this.IsReceived)); - } - - protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberNameAttribute] string propertyName = "") - { - this.PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); - } - } - -#pragma warning disable 649 // field initialization is optional in user code - - private struct Template - { - internal System.Boolean IsReceived; - internal DurableTask.TaskMessage TaskMessage; - } -#pragma warning restore 649 - } -} \ No newline at end of file From 9a074ff77140fcaff47bf7f186269e35ff92b5ce Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 16 Sep 2016 10:35:46 -0700 Subject: [PATCH 076/210] A reasonable (according to me) compromise to keep the class immutable (in spirit) and make data contract serialization work. (For reliability over node failures) [The other choices are : - to use the same code generation for immutable and use some other serialization technique and write winfab state serializer for that serialization mechanism - or avoid using immutable and risk introducing hard to catch bugs Also, the performance of data contract serialization doesn't seem to be too bad - hence I removed the comment. If we see that serialization is indeed bottleneck when we do perf testing, we can fix that. --- src/DurableTask.ServiceFabric/FabricOrchestrationService.cs | 1 - .../FabricOrchestrationServiceClient.cs | 1 - src/DurableTask.ServiceFabric/PersistentSession.cs | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index c147a3d81..1d54b0f58 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -21,7 +21,6 @@ namespace DurableTask.ServiceFabric using DurableTask.Common; using DurableTask.Tracking; using Microsoft.ServiceFabric.Data; - using Microsoft.ServiceFabric.Data.Collections; public class FabricOrchestrationService : IOrchestrationService { diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index aad543c67..70715887b 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -19,7 +19,6 @@ namespace DurableTask.ServiceFabric using System.Threading.Tasks; using DurableTask.History; using Microsoft.ServiceFabric.Data; - using Microsoft.ServiceFabric.Data.Collections; public class FabricOrchestrationServiceClient : IOrchestrationServiceClient { diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index d3c2fd6f7..ca511e67a 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -41,7 +41,7 @@ public sealed partial class PersistentSession [DataMember] public IEnumerable ScheduledMessages { get; private set; } - public bool IsLocked { get; private set; } + public bool IsLocked { get; } [OnDeserialized] private void OnDeserialized(StreamingContext context) From b607bb0fd96e988d5871f5a904baf9f96831158f Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 16 Sep 2016 10:35:46 -0700 Subject: [PATCH 077/210] Minor change to create state manager transaction only if needed. --- src/DurableTask.ServiceFabric/ActivitiesProvider.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs index 64a97d6e5..d21cc54b0 100644 --- a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs +++ b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs @@ -64,10 +64,10 @@ public async Task GetNextWorkItem(TimeSpan receiveTimeout) Stopwatch timer = Stopwatch.StartNew(); while (timer.Elapsed < receiveTimeout && !this.cancellationTokenSource.IsCancellationRequested) { - using (var txn = this.stateManager.CreateTransaction()) + string activityId; + if (this.inMemoryQueue.TryDequeue(out activityId)) { - string activityId; - if (this.inMemoryQueue.TryDequeue(out activityId)) + using (var txn = this.stateManager.CreateTransaction()) { var activity = await this.activityQueue.TryGetValueAsync(txn, activityId); if (activity.HasValue) @@ -77,6 +77,7 @@ public async Task GetNextWorkItem(TimeSpan receiveTimeout) throw new Exception("Internal server error"); } } + await Task.Delay(100, this.cancellationTokenSource.Token); await PopulateInMemoryActivities(); } From 82161314aa40a7c14323d632cee7ba60f4f6b03e Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 17:03:52 -0700 Subject: [PATCH 078/210] Fixing bad rebase. --- .../ActivitiesProvider.cs | 8 ++++++-- .../FabricOrchestrationService.cs | 16 +--------------- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs index d21cc54b0..d62215e4b 100644 --- a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs +++ b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs @@ -59,7 +59,7 @@ public void Stop() this.cancellationTokenSource.Cancel(); } - public async Task GetNextWorkItem(TimeSpan receiveTimeout) + public async Task GetNextWorkItem(TimeSpan receiveTimeout) { Stopwatch timer = Stopwatch.StartNew(); while (timer.Elapsed < receiveTimeout && !this.cancellationTokenSource.IsCancellationRequested) @@ -72,7 +72,11 @@ public async Task GetNextWorkItem(TimeSpan receiveTimeout) var activity = await this.activityQueue.TryGetValueAsync(txn, activityId); if (activity.HasValue) { - return activity.Value; + return new TaskActivityWorkItem() + { + Id = activityId, + TaskMessage = activity.Value + }; } throw new Exception("Internal server error"); } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 1d54b0f58..4e87d324d 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -45,11 +45,9 @@ public FabricOrchestrationService(IReliableStateManager stateManager, SessionsPr public async Task StartAsync() { this.activitiesProvider = new ActivitiesProvider(this.stateManager); - this.orchestrationProvider = new SessionsProvider(stateManager); await this.activitiesProvider.StartAsync(); await this.instanceStore.StartAsync(); await this.orchestrationProvider.StartAsync(); - await this.activitiesProvider.StartAsync(); } public Task StopAsync() @@ -59,7 +57,6 @@ public Task StopAsync() public async Task StopAsync(bool isForced) { - this.activitiesProvider.Stop(); this.orchestrationProvider.Stop(); await this.instanceStore.StopAsync(isForced); this.activitiesProvider.Stop(); @@ -215,18 +212,7 @@ public async Task ReleaseTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkIte // Note: Do not rely on cancellationToken parameter to this method because the top layer does not yet implement any cancellation. public async Task LockNextTaskActivityWorkItem(TimeSpan receiveTimeout, CancellationToken cancellationToken) { - var currentActivity = await this.activitiesProvider.GetNextWorkItem(receiveTimeout); - - if (currentActivity != null) - { - return new TaskActivityWorkItem() - { - Id = Guid.NewGuid().ToString(), //Todo: Do we need to persist this in activity queue? - TaskMessage = currentActivity - }; - } - - return null; + return await this.activitiesProvider.GetNextWorkItem(receiveTimeout); } public async Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workItem, TaskMessage responseMessage) From 61c23f94e100f986b36d9a11e3377b7c07d4f3ad Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 079/210] Some improvement that would avoid locking/enumerating for activities. Also the class is templatized , perhaps I can evolve the same to use for sessions too with some more changes. --- .../ActivitiesProvider.cs | 149 ----------------- .../DurableTask.ServiceFabric.csproj | 2 +- .../FabricOrchestrationService.cs | 29 +++- .../PeekLockQueue.cs | 152 ++++++++++++++++++ 4 files changed, 174 insertions(+), 158 deletions(-) delete mode 100644 src/DurableTask.ServiceFabric/ActivitiesProvider.cs create mode 100644 src/DurableTask.ServiceFabric/PeekLockQueue.cs diff --git a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs b/src/DurableTask.ServiceFabric/ActivitiesProvider.cs deleted file mode 100644 index d62215e4b..000000000 --- a/src/DurableTask.ServiceFabric/ActivitiesProvider.cs +++ /dev/null @@ -1,149 +0,0 @@ -// ---------------------------------------------------------------------------------- -// Copyright Microsoft Corporation -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ---------------------------------------------------------------------------------- - -namespace DurableTask.ServiceFabric -{ - using System; - using System.Collections.Concurrent; - using System.Collections.Generic; - using System.Diagnostics; - using System.Threading; - using System.Threading.Tasks; - using Microsoft.ServiceFabric.Data; - using Microsoft.ServiceFabric.Data.Collections; - - //Todo: Refactor common components of this class and SessionsProvider - class ActivitiesProvider - { - readonly IReliableStateManager stateManager; - readonly CancellationTokenSource cancellationTokenSource; - - IReliableDictionary activityQueue; - ConcurrentQueue inMemoryQueue = new ConcurrentQueue(); - ConcurrentDictionary lockTable = new ConcurrentDictionary(); - //bool newMessagesInStore; - //object syncLock = new object(); - - public ActivitiesProvider(IReliableStateManager stateManager) - { - if (stateManager == null) - { - throw new ArgumentNullException(nameof(stateManager)); - } - - this.stateManager = stateManager; - this.cancellationTokenSource = new CancellationTokenSource(); - } - - public async Task StartAsync() - { - this.activityQueue = await this.stateManager.GetOrAddAsync>(Constants.ActivitiesQueueName); - //lock (syncLock) - //{ - // this.newMessagesInStore = true; - //} - } - - public void Stop() - { - this.cancellationTokenSource.Cancel(); - } - - public async Task GetNextWorkItem(TimeSpan receiveTimeout) - { - Stopwatch timer = Stopwatch.StartNew(); - while (timer.Elapsed < receiveTimeout && !this.cancellationTokenSource.IsCancellationRequested) - { - string activityId; - if (this.inMemoryQueue.TryDequeue(out activityId)) - { - using (var txn = this.stateManager.CreateTransaction()) - { - var activity = await this.activityQueue.TryGetValueAsync(txn, activityId); - if (activity.HasValue) - { - return new TaskActivityWorkItem() - { - Id = activityId, - TaskMessage = activity.Value - }; - } - throw new Exception("Internal server error"); - } - } - - await Task.Delay(100, this.cancellationTokenSource.Token); - await PopulateInMemoryActivities(); - } - return null; - } - - public async Task CompleteWorkItem(ITransaction transaction, TaskActivityWorkItem workItem) - { - await this.activityQueue.TryRemoveAsync(transaction, workItem.Id); - //Todo: Need to cleanup the lock table only after the transaction commit... - //bool ignored; - //this.lockTable.TryRemove(workItem.Id, out ignored); - } - - public async Task AppendBatch(ITransaction transaction, IList messages) - { - if (messages.Count > 0) - { - //lock (syncLock) - //{ - // this.newMessagesInStore = true; - //} - foreach (var message in messages) - { - var id = Guid.NewGuid().ToString(); - await this.activityQueue.AddAsync(transaction, id, message); - } - } - } - - async Task PopulateInMemoryActivities() - { - //var shouldFetchActivitiesInMemory = false; - //lock (syncLock) - //{ - // if (this.newMessagesInStore) - // { - // this.newMessagesInStore = false; - // shouldFetchActivitiesInMemory = true; - // } - //} - - //if (shouldFetchActivitiesInMemory) - if (!this.cancellationTokenSource.IsCancellationRequested) - { - using (var txn = this.stateManager.CreateTransaction()) - { - var enumerable = await this.activityQueue.CreateEnumerableAsync(txn, EnumerationMode.Unordered); - using (var enumerator = enumerable.GetAsyncEnumerator()) - { - while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) - { - var activityId = enumerator.Current.Key; - if (!this.lockTable.ContainsKey(activityId)) - { - this.inMemoryQueue.Enqueue(activityId); - this.lockTable.TryAdd(activityId, true); - } - } - } - } - } - } - } -} diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 28197568e..db672dff6 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -73,13 +73,13 @@ - + PersistentSession.cs diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 4e87d324d..79d221375 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -16,6 +16,7 @@ namespace DurableTask.ServiceFabric using System; using System.Collections.Generic; using System.Collections.Immutable; + using System.Linq; using System.Threading; using System.Threading.Tasks; using DurableTask.Common; @@ -28,7 +29,7 @@ public class FabricOrchestrationService : IOrchestrationService IFabricOrchestrationServiceInstanceStore instanceStore; SessionsProvider orchestrationProvider; - ActivitiesProvider activitiesProvider; + PeekLockQueue activitiesProvider; public FabricOrchestrationService(IReliableStateManager stateManager, SessionsProvider orchestrationProvider, IFabricOrchestrationServiceInstanceStore instanceStore) { @@ -44,7 +45,7 @@ public FabricOrchestrationService(IReliableStateManager stateManager, SessionsPr public async Task StartAsync() { - this.activitiesProvider = new ActivitiesProvider(this.stateManager); + this.activitiesProvider = new PeekLockQueue(this.stateManager, Constants.ActivitiesQueueName); await this.activitiesProvider.StartAsync(); await this.instanceStore.StartAsync(); await this.orchestrationProvider.StartAsync(); @@ -59,7 +60,7 @@ public async Task StopAsync(bool isForced) { this.orchestrationProvider.Stop(); await this.instanceStore.StopAsync(isForced); - this.activitiesProvider.Stop(); + await this.activitiesProvider.StopAsync(); } public Task CreateAsync() @@ -160,7 +161,8 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( using (var txn = this.stateManager.CreateTransaction()) { - await this.activitiesProvider.AppendBatch(txn, outboundMessages); + var activityMessages = outboundMessages.Select(m => new Message(Guid.NewGuid().ToString(), m)).ToList(); + await this.activitiesProvider.SendBatchBeginAsync(txn, activityMessages); await this.orchestrationProvider.CompleteAndUpdateSession(txn, workItem.InstanceId, newOrchestrationRuntimeState, timerMessages); @@ -181,6 +183,7 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( } await txn.CommitAsync(); + this.activitiesProvider.SendBatchComplete(activityMessages); } } @@ -212,14 +215,25 @@ public async Task ReleaseTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkIte // Note: Do not rely on cancellationToken parameter to this method because the top layer does not yet implement any cancellation. public async Task LockNextTaskActivityWorkItem(TimeSpan receiveTimeout, CancellationToken cancellationToken) { - return await this.activitiesProvider.GetNextWorkItem(receiveTimeout); + var message = await this.activitiesProvider.ReceiveAsync(receiveTimeout); + + if (message != null) + { + return new TaskActivityWorkItem() + { + Id = message.Key, + TaskMessage = message.Value + }; + } + + return null; } public async Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workItem, TaskMessage responseMessage) { using (var txn = this.stateManager.CreateTransaction()) { - await this.activitiesProvider.CompleteWorkItem(txn, workItem); + await this.activitiesProvider.CompleteAsync(txn, workItem.Id); await this.orchestrationProvider.AppendMessageAsync(txn, responseMessage); await txn.CommitAsync(); } @@ -227,8 +241,7 @@ public async Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workIte public Task AbandonTaskActivityWorkItemAsync(TaskActivityWorkItem workItem) { - //Todo: Implement to add back to in-memory queue - return Task.FromResult(null); + return this.activitiesProvider.AandonAsync(workItem.Id); } public bool ProcessWorkItemSynchronously => false; diff --git a/src/DurableTask.ServiceFabric/PeekLockQueue.cs b/src/DurableTask.ServiceFabric/PeekLockQueue.cs new file mode 100644 index 000000000..564db20d7 --- /dev/null +++ b/src/DurableTask.ServiceFabric/PeekLockQueue.cs @@ -0,0 +1,152 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace DurableTask.ServiceFabric +{ + using System; + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.Diagnostics; + using System.Runtime.Serialization; + using System.Threading; + using System.Threading.Tasks; + using Microsoft.ServiceFabric.Data; + using Microsoft.ServiceFabric.Data.Collections; + + class PeekLockQueue where TKey : IComparable, IEquatable + { + readonly IReliableStateManager stateManager; + readonly string storeName; + readonly CancellationTokenSource cancellationTokenSource; + + IReliableDictionary store; + ConcurrentQueue inMemoryQueue = new ConcurrentQueue(); + + public PeekLockQueue(IReliableStateManager stateManager, string storeName) + { + this.stateManager = stateManager; + this.storeName = storeName; + this.cancellationTokenSource = new CancellationTokenSource(); + } + + public async Task StartAsync() + { + this.store = await this.stateManager.GetOrAddAsync>(this.storeName); + + using (var txn = this.stateManager.CreateTransaction()) + { + //Todo: Check count first + var enumerable = await this.store.CreateEnumerableAsync(txn, EnumerationMode.Unordered); + using (var enumerator = enumerable.GetAsyncEnumerator()) + { + while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) + { + this.inMemoryQueue.Enqueue(enumerator.Current.Key); + } + } + } + } + + public Task StopAsync() + { + this.cancellationTokenSource.Cancel(); + return Task.FromResult(null); + } + + public async Task> ReceiveAsync(TimeSpan receiveTimeout) + { + Stopwatch timer = Stopwatch.StartNew(); + while (timer.Elapsed < receiveTimeout && !this.cancellationTokenSource.IsCancellationRequested) + { + TKey activityId; + if (this.inMemoryQueue.TryDequeue(out activityId)) + { + using (var txn = this.stateManager.CreateTransaction()) + { + var activity = await this.store.TryGetValueAsync(txn, activityId); + if (activity.HasValue) + { + return new Message(activityId, activity.Value); + } + throw new Exception("Internal server error"); + } + } + + //Todo : Can use a signal mechanism between send and receive + await Task.Delay(100, this.cancellationTokenSource.Token); + } + return null; + } + + public Task CompleteAsync(ITransaction tx, TKey key) + { + return this.store.TryRemoveAsync(tx, key); + } + + /// + /// Caller has to pass in a transaction and must call SendComplete with the same item + /// after the transaction commit succeeded. + /// + public Task SendBeginAsync(ITransaction tx, Message item) + { + return this.store.TryAddAsync(tx, item.Key, item.Value); + } + + public void SendComplete(Message item) + { + this.inMemoryQueue.Enqueue(item.Key); + } + + /// + /// Caller has to pass in a transaction and must call SendBatchComplete with the same items + /// after the transaction commit succeeded. + /// + public async Task SendBatchBeginAsync(ITransaction tx, IEnumerable> items) + { + foreach (var item in items) + { + await this.SendBeginAsync(tx, item); + } + } + + public void SendBatchComplete(IEnumerable> items) + { + foreach (var item in items) + { + this.SendComplete(item); + } + } + + public Task AandonAsync(TKey key) + { + this.inMemoryQueue.Enqueue(key); + return Task.FromResult(null); + } + } + + [DataContract] + class Message where TKey : IComparable, IEquatable + { + public Message(TKey key, TValue value) + { + Key = key; + Value = value; + } + + [DataMember] + public TKey Key { get; private set; } + + [DataMember] + public TValue Value { get; private set; } + } +} From 529457b4e0c26c03af1ea84f90c3a96a4dd532db Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 080/210] Adding a todo identified when doing node failure. --- src/DurableTask.ServiceFabric/FabricOrchestrationService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 79d221375..28e85f094 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -231,6 +231,7 @@ public async Task LockNextTaskActivityWorkItem(TimeSpan re public async Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workItem, TaskMessage responseMessage) { + //Todo : If we check for cancellation token, then we could avoid harmless FabricNotPrimaryExceptions that happen when primary node switches using (var txn = this.stateManager.CreateTransaction()) { await this.activitiesProvider.CompleteAsync(txn, workItem.Id); From bd9c71a8fb5efc2cafbdc5c3a2f7b12322a6507d Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 081/210] Refactor -> Rename. --- src/DurableTask.ServiceFabric/PeekLockQueue.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DurableTask.ServiceFabric/PeekLockQueue.cs b/src/DurableTask.ServiceFabric/PeekLockQueue.cs index 564db20d7..4b2e04091 100644 --- a/src/DurableTask.ServiceFabric/PeekLockQueue.cs +++ b/src/DurableTask.ServiceFabric/PeekLockQueue.cs @@ -68,15 +68,15 @@ public async Task> ReceiveAsync(TimeSpan receiveTimeout) Stopwatch timer = Stopwatch.StartNew(); while (timer.Elapsed < receiveTimeout && !this.cancellationTokenSource.IsCancellationRequested) { - TKey activityId; - if (this.inMemoryQueue.TryDequeue(out activityId)) + TKey key; + if (this.inMemoryQueue.TryDequeue(out key)) { using (var txn = this.stateManager.CreateTransaction()) { - var activity = await this.store.TryGetValueAsync(txn, activityId); - if (activity.HasValue) + var result = await this.store.TryGetValueAsync(txn, key); + if (result.HasValue) { - return new Message(activityId, activity.Value); + return new Message(key, result.Value); } throw new Exception("Internal server error"); } From 0b24d2ab71cd46906131ea5274973f70ab4c374d Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 082/210] Minor change to test. --- Test/DurableTask.ServiceFabric.Test/StressTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.Test/StressTests.cs b/Test/DurableTask.ServiceFabric.Test/StressTests.cs index 7ff5c8ec8..17f7039cd 100644 --- a/Test/DurableTask.ServiceFabric.Test/StressTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/StressTests.cs @@ -39,14 +39,14 @@ public async Task ExecuteStressTest() { NumberOfParallelTasks = 10, NumberOfSerialTasks = 5, - MaxDelayInMinutes = 5 + MaxDelayInMinutes = 5 //Todo: This is really seconds... rename it... } }; Console.WriteLine($"Orchestration getting scheduled: {DateTime.Now}"); Stopwatch stopWatch = Stopwatch.StartNew(); - var state = await serviceClient.RunDriverOrchestrationAsync(driverConfig, TimeSpan.FromHours(24)); + var state = await serviceClient.RunDriverOrchestrationAsync(driverConfig, TimeSpan.FromMinutes(5)); stopWatch.Stop(); Console.WriteLine($"Orchestration Status: {state.OrchestrationStatus}"); From bc8ef488796abafdd1e52420ee47d78fd00d519f Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 083/210] Improvement to PersistentSession API. --- .../PersistentSessionTests.cs | 6 +-- .../FabricOrchestrationService.cs | 2 +- .../PersistentSession.api.cs | 42 +++++++++---------- .../PersistentSession.cs | 35 +++++++++++----- .../SessionsProvider.cs | 2 +- 5 files changed, 51 insertions(+), 36 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs index d386cfa8c..abff13fdc 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs @@ -72,9 +72,9 @@ public void SerializationTest() Assert.IsNotNull(deserialized); Assert.AreEqual("testSession", deserialized.SessionId); Assert.IsFalse(deserialized.IsLocked); - Assert.AreEqual(numberOfItemsInCollections*2 + 2, deserialized.SessionState.Count()); - Assert.AreEqual(numberOfItemsInCollections, deserialized.Messages.Count()); - Assert.AreEqual(numberOfItemsInCollections, deserialized.ScheduledMessages.Count()); + Assert.AreEqual(numberOfItemsInCollections*2 + 2, deserialized.SessionState.Count); + Assert.AreEqual(numberOfItemsInCollections, deserialized.Messages.Count); + Assert.AreEqual(numberOfItemsInCollections, deserialized.ScheduledMessages.Count); } } } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 28e85f094..f67b7da6b 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -136,7 +136,7 @@ public async Task LockNextTaskOrchestrationWorkItemAs { NewMessages = newMessages, InstanceId = currentSession.SessionId, - OrchestrationRuntimeState = new OrchestrationRuntimeState(currentSession.SessionState.ToImmutableList()) + OrchestrationRuntimeState = new OrchestrationRuntimeState(currentSession.SessionState) }; } diff --git a/src/DurableTask.ServiceFabric/PersistentSession.api.cs b/src/DurableTask.ServiceFabric/PersistentSession.api.cs index 48561046d..be840c62e 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.api.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.api.cs @@ -24,7 +24,7 @@ public sealed partial class PersistentSession // Todo: Can optimize in a few other ways, for now, something that works public PersistentSession FireScheduledMessages() { - var messagesBuilder = this.Messages.ToImmutableList().ToBuilder(); + var messagesBuilder = this.Messages.ToBuilder(); var remainingScheduledMessagesBuilder = ImmutableList.Empty.ToBuilder(); bool changed = false; @@ -53,7 +53,7 @@ public PersistentSession FireScheduledMessages() if (changed) { - return Create(this.SessionId, this.SessionState.ToImmutableList(), messagesBuilder.ToImmutableList(), remainingScheduledMessagesBuilder.ToImmutableList(), this.IsLocked); + return Create(this.SessionId, this.SessionState, messagesBuilder.ToImmutableList(), remainingScheduledMessagesBuilder.ToImmutableList(), this.IsLocked); } return this; @@ -61,44 +61,44 @@ public PersistentSession FireScheduledMessages() public PersistentSession ReceiveMessages() { - var messages = this.Messages.ToImmutableList().ToBuilder().ConvertAll(m => ReceivableTaskMessage.Create(m.TaskMessage, isReceived: true)); - return Create(this.SessionId, this.SessionState.ToImmutableList(), messages, this.ScheduledMessages.ToImmutableList(), isLocked: true); + var newMessages = this.Messages.ToBuilder().ConvertAll(m => ReceivableTaskMessage.Create(m.TaskMessage, isReceived: true)); + return Create(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages, isLocked: true); } - public PersistentSession CompleteMessages(OrchestrationRuntimeState newState, IList newScheduledMessages) + public PersistentSession CompleteMessages(OrchestrationRuntimeState newState, IList addedScheduledMessages) { - var messages = this.Messages.ToImmutableList().RemoveAll(m => m.IsReceived); - var sessionState = newState?.Events.ToImmutableList(); - var scheduledMessages = this.ScheduledMessages; - if (newScheduledMessages?.Count > 0) + var newMessages = this.Messages.RemoveAll(m => m.IsReceived); + var newSessionState = newState?.Events.ToImmutableList(); + var newScheduledMessages = this.ScheduledMessages; + if (addedScheduledMessages?.Count > 0) { - scheduledMessages = this.ScheduledMessages.ToImmutableList().AddRange(newScheduledMessages.Select(tm => ReceivableTaskMessage.Create(tm))); + newScheduledMessages = this.ScheduledMessages.AddRange(addedScheduledMessages.Select(tm => ReceivableTaskMessage.Create(tm))); } - return Create(this.SessionId, sessionState, messages, scheduledMessages.ToImmutableList(), isLocked: false); + return Create(this.SessionId, newSessionState, newMessages, newScheduledMessages, isLocked: false); } public PersistentSession AppendMessage(TaskMessage message) { - var messages = this.Messages.ToImmutableList().Add(ReceivableTaskMessage.Create(message)); - return Create(this.SessionId, this.SessionState.ToImmutableList(), messages, this.ScheduledMessages.ToImmutableList(), this.IsLocked); + var newMessages = this.Messages.Add(ReceivableTaskMessage.Create(message)); + return Create(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages, this.IsLocked); } - public PersistentSession AppendMessageBatch(IEnumerable newMessages) + public PersistentSession AppendMessageBatch(IEnumerable addedMessages) { - var messages = this.Messages.ToImmutableList().AddRange(newMessages.Select(m => ReceivableTaskMessage.Create(m))); - return Create(this.SessionId, this.SessionState.ToImmutableList(), messages, this.ScheduledMessages.ToImmutableList(), this.IsLocked); + var newMessages = this.Messages.AddRange(addedMessages.Select(m => ReceivableTaskMessage.Create(m))); + return Create(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages, this.IsLocked); } public static PersistentSession CreateWithNewMessage(string sessionId, TaskMessage newMessage) { - var messages = ImmutableList.Empty.Add(ReceivableTaskMessage.Create(newMessage)); - return PersistentSession.Create(sessionId, sessionState: null, messages: messages, scheduledMessages: null, isLocked: false); + var newMessages = ImmutableList.Empty.Add(ReceivableTaskMessage.Create(newMessage)); + return Create(sessionId, sessionState: null, messages: newMessages, scheduledMessages: null, isLocked: false); } - public static PersistentSession CreateWithNewMessages(string sessionId, IEnumerable newMessages) + public static PersistentSession CreateWithNewMessages(string sessionId, IEnumerable allMessages) { - var messages = ImmutableList.Empty.AddRange(newMessages.Select(newMessage => ReceivableTaskMessage.Create(newMessage))); - return PersistentSession.Create(sessionId, sessionState: null, messages: messages, scheduledMessages: null, isLocked: false); + var newMessages = ImmutableList.Empty.AddRange(allMessages.Select(newMessage => ReceivableTaskMessage.Create(newMessage))); + return Create(sessionId, sessionState: null, messages: newMessages, scheduledMessages: null, isLocked: false); } } } diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index ca511e67a..39decb985 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -31,32 +31,43 @@ public sealed partial class PersistentSession // Note: The properties below are marked IEnumerable but not // IImmutableList because DataContract serialization cannot deserialize the latter. - // They should really be treated like IImmutableList in the code for this class. + // Except for the constructor and serialization methods, rest of the code in this class + // should use only the public immutable list members. + + /// + /// Do not use except in the constructor or serialization methods, use property instead. + /// [DataMember] - public IEnumerable SessionState { get; private set; } + IEnumerable sessionState { get; set; } + /// + /// Do not use except in the constructor or serialization methods, use property instead. + /// [DataMember] - public IEnumerable Messages { get; private set; } + IEnumerable messages { get; set; } + /// + /// Do not use except in the constructor or serialization methods, use property instead. + /// [DataMember] - public IEnumerable ScheduledMessages { get; private set; } + IEnumerable scheduledMessages { get; set; } public bool IsLocked { get; } [OnDeserialized] private void OnDeserialized(StreamingContext context) { - this.SessionState = this.SessionState.ToImmutableList(); - this.Messages = this.Messages.ToImmutableList(); - this.ScheduledMessages = this.ScheduledMessages.ToImmutableList(); + this.sessionState = this.sessionState.ToImmutableList(); + this.messages = this.messages.ToImmutableList(); + this.scheduledMessages = this.scheduledMessages.ToImmutableList(); } private PersistentSession(string sessionId, IImmutableList sessionState, IImmutableList messages, IImmutableList scheduledMessages, bool isLocked) { this.SessionId = sessionId; - this.SessionState = sessionState ?? ImmutableList.Empty; - this.Messages = messages ?? ImmutableList.Empty; - this.ScheduledMessages = scheduledMessages ?? ImmutableList.Empty; + this.sessionState = sessionState ?? ImmutableList.Empty; + this.messages = messages ?? ImmutableList.Empty; + this.scheduledMessages = scheduledMessages ?? ImmutableList.Empty; this.IsLocked = isLocked; } @@ -64,6 +75,10 @@ public static PersistentSession Create(string sessionId, IImmutableList SessionState => this.sessionState.ToImmutableList(); + public ImmutableList Messages => this.messages.ToImmutableList(); + public ImmutableList ScheduledMessages => this.scheduledMessages.ToImmutableList(); } [DataContract] diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 1ef02cade..1655bf03a 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -62,7 +62,7 @@ async Task ProcessScheduledMessages() while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) { var entry = enumerator.Current; - if (entry.Value.ScheduledMessages.Any()) + if (entry.Value.ScheduledMessages.Count > 0) { scheduledMessageSessions.Add(entry.Key); } From a17e2ca7c1e96acea01cfe07fb0e2370d2a0791b Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 084/210] Clearing some simple todo's. --- .../FabricOrchestrationInstanceStore.cs | 4 +--- .../FabricOrchestrationService.cs | 1 - src/DurableTask.ServiceFabric/PeekLockQueue.cs | 16 ++++++++++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs index 14c6b6c47..4d51f9852 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs @@ -74,9 +74,7 @@ public async Task WriteEntitesAsync(ITransaction transaction, IEnumerable state.State); diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index f67b7da6b..c9dc3cb63 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -92,7 +92,6 @@ public async Task DeleteAsync(bool deleteInstanceStore) public bool IsMaxMessageCountExceeded(int currentMessageCount, OrchestrationRuntimeState runtimeState) { - //Todo: Do we need to enforce a limit here? return false; } diff --git a/src/DurableTask.ServiceFabric/PeekLockQueue.cs b/src/DurableTask.ServiceFabric/PeekLockQueue.cs index 4b2e04091..833316fa8 100644 --- a/src/DurableTask.ServiceFabric/PeekLockQueue.cs +++ b/src/DurableTask.ServiceFabric/PeekLockQueue.cs @@ -43,15 +43,19 @@ public async Task StartAsync() { this.store = await this.stateManager.GetOrAddAsync>(this.storeName); - using (var txn = this.stateManager.CreateTransaction()) + using (var tx = this.stateManager.CreateTransaction()) { - //Todo: Check count first - var enumerable = await this.store.CreateEnumerableAsync(txn, EnumerationMode.Unordered); - using (var enumerator = enumerable.GetAsyncEnumerator()) + var count = await this.store.GetCountAsync(tx); + + if (count > 0) { - while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) + var enumerable = await this.store.CreateEnumerableAsync(tx, EnumerationMode.Unordered); + using (var enumerator = enumerable.GetAsyncEnumerator()) { - this.inMemoryQueue.Enqueue(enumerator.Current.Key); + while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) + { + this.inMemoryQueue.Enqueue(enumerator.Current.Key); + } } } } From 90cdc3aa11dde9ccffd34c6dcc465334b93d9aba Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 085/210] Adding check for invalidating creating an orchestration when another one with same id is already running. --- .../FabricOrchestrationService.cs | 2 +- .../FabricOrchestrationServiceClient.cs | 10 +++++-- .../SessionsProvider.cs | 27 ++++++++++++++----- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index c9dc3cb63..1ef4adcde 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -198,7 +198,7 @@ public async Task ReleaseTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkIte { using (var txn = this.stateManager.CreateTransaction()) { - await this.orchestrationProvider.ReleaseSession(txn, workItem.InstanceId); + await this.orchestrationProvider.DropSession(txn, workItem.InstanceId); await txn.CommitAsync(); ProviderEventSource.Instance.LogOrchestrationFinished(workItem.InstanceId, workItem.OrchestrationRuntimeState.OrchestrationStatus.ToString(), diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index 70715887b..6c3ed2159 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -40,10 +40,16 @@ public async Task CreateTaskOrchestrationAsync(TaskMessage creationMessage) throw new Exception("Invalid creation message"); } - //Todo: Need to throw if the same instance and execution id is already running + var instance = creationMessage.OrchestrationInstance; + + //Todo: Does this need to throw only if the orchestration is not running Or an orchestration was ever created before with the same id? + if (await this.orchestrationProvider.SessionExists(instance.InstanceId)) + { + throw new InvalidOperationException($"An orchestration with id '{creationMessage.OrchestrationInstance.InstanceId}' is already running."); + } await this.SendTaskOrchestrationMessageAsync(creationMessage); - ProviderEventSource.Instance.LogOrchestrationCreated(creationMessage.OrchestrationInstance.InstanceId); + ProviderEventSource.Instance.LogOrchestrationCreated(instance.InstanceId); } public async Task SendTaskOrchestrationMessageAsync(TaskMessage message) diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 1655bf03a..2aaff85d3 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -129,11 +129,7 @@ await this.orchestrations.AddOrUpdateAsync(transaction, sessionId, NewSessionFac public async Task AppendMessageAsync(ITransaction transaction, TaskMessage newMessage) { - //Workaround to avoid client sending a new message before StartAsync on service is done - if (this.orchestrations == null) - { - this.orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); - } + await EnsureOrchestrationStoreInitialized(); Func newSessionFactory = (sId) => PersistentSession.CreateWithNewMessage(sId, newMessage); @@ -158,11 +154,30 @@ await this.orchestrations.AddOrUpdateAsync(transaction, group.Key, } } - public async Task ReleaseSession(ITransaction transaction, string sessionId) + public async Task DropSession(ITransaction transaction, string sessionId) { await this.orchestrations.TryRemoveAsync(transaction, sessionId); } + public async Task SessionExists(string sessionId) + { + await EnsureOrchestrationStoreInitialized(); + + using (var txn = this.stateManager.CreateTransaction()) + { + return await this.orchestrations.ContainsKeyAsync(txn, sessionId); + } + } + + async Task EnsureOrchestrationStoreInitialized() + { + //Workaround to avoid client sending a new message before StartAsync on service is done + if (this.orchestrations == null) + { + this.orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); + } + } + async Task PopulateInMemorySessions() { if (!this.cancellationTokenSource.IsCancellationRequested) From 72f051f17af00702f78e757a06a77a86db87567a Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 086/210] Making changes to tests so that I can keep the source repository behavior while using a different variation for my tests. --- .../Program.cs | 2 +- .../StressTests.cs | 3 +- .../DurableTask.Test.Orchestrations.csproj | 1 + .../Stress/FixedTimeWaitingTask.cs | 27 ++++++++++ .../Stress/TestOrchestration.cs | 54 ++++++++++++++++--- .../Stress/TestOrchestrationData.cs | 9 +++- .../Stress/TestTask.cs | 8 +-- .../Stress/TestTaskData.cs | 4 +- test/DurableTask.Stress.Tests/Program.cs | 2 +- 9 files changed, 93 insertions(+), 17 deletions(-) create mode 100644 Test/DurableTask.Test.Orchestrations/Stress/FixedTimeWaitingTask.cs diff --git a/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs b/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs index f1ac99ff4..a0f7ff47d 100644 --- a/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs +++ b/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs @@ -99,7 +99,7 @@ static async Task RunOrchestrations(CancellationToken cancellationToken) { NumberOfParallelTasks = 15, NumberOfSerialTasks = 5, - MaxDelayInMinutes = 0 + MaxDelayTime = 0 }; totalRequests++; diff --git a/Test/DurableTask.ServiceFabric.Test/StressTests.cs b/Test/DurableTask.ServiceFabric.Test/StressTests.cs index 17f7039cd..e1af3c8ef 100644 --- a/Test/DurableTask.ServiceFabric.Test/StressTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/StressTests.cs @@ -39,7 +39,8 @@ public async Task ExecuteStressTest() { NumberOfParallelTasks = 10, NumberOfSerialTasks = 5, - MaxDelayInMinutes = 5 //Todo: This is really seconds... rename it... + MaxDelayTime = 5, + DelayUnit = TimeSpan.FromSeconds(1) } }; diff --git a/Test/DurableTask.Test.Orchestrations/DurableTask.Test.Orchestrations.csproj b/Test/DurableTask.Test.Orchestrations/DurableTask.Test.Orchestrations.csproj index 12483e328..a37a218ea 100644 --- a/Test/DurableTask.Test.Orchestrations/DurableTask.Test.Orchestrations.csproj +++ b/Test/DurableTask.Test.Orchestrations/DurableTask.Test.Orchestrations.csproj @@ -45,6 +45,7 @@ + diff --git a/Test/DurableTask.Test.Orchestrations/Stress/FixedTimeWaitingTask.cs b/Test/DurableTask.Test.Orchestrations/Stress/FixedTimeWaitingTask.cs new file mode 100644 index 000000000..6425608f4 --- /dev/null +++ b/Test/DurableTask.Test.Orchestrations/Stress/FixedTimeWaitingTask.cs @@ -0,0 +1,27 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Threading.Tasks; + +namespace DurableTask.Test.Orchestrations.Stress +{ + public sealed class FixedTimeWaitingTask : AsyncTaskActivity + { + protected override async Task ExecuteAsync(TaskContext context, TestTaskData input) + { + await Task.Delay(input.MaxDelay); + return 1; + } + } +} diff --git a/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestration.cs b/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestration.cs index 882fa785d..1d939e317 100644 --- a/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestration.cs +++ b/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestration.cs @@ -21,35 +21,73 @@ namespace DurableTask.Test.Orchestrations.Stress public class TestOrchestration : TaskOrchestration { + readonly Dictionary _knownActivityTypes = new Dictionary() + { + {typeof(TestTask).Name, new ActivityInformation(typeof(TestTask), false) }, + {typeof(FixedTimeWaitingTask).Name, new ActivityInformation(typeof(FixedTimeWaitingTask), true) }, + }; + public override async Task RunTask(OrchestrationContext context, TestOrchestrationData data) { + var activityInfo = GetActivityInfo(data); + var maxDelayTimeSpan = TimeSpan.FromMilliseconds((data.DelayUnit ?? TimeSpan.FromMinutes(1)).TotalMilliseconds * data.MaxDelayTime); + int result = 0; List> results = new List>(); int i = 0; int j = 0; for (; i < data.NumberOfParallelTasks; i++) { - results.Add(context.ScheduleTask(typeof(TestTask), new TestTaskData + results.Add(context.ScheduleTask(activityInfo.ActivityType, new TestTaskData { - TaskId = "ParallelTask: " + i.ToString(), - MaxDelayInMinutes = data.MaxDelayInMinutes, + TaskId = "ParallelTask: " + i, + MaxDelay = maxDelayTimeSpan, })); } int[] counters = await Task.WhenAll(results.ToArray()); - result = counters.Max(); + result = activityInfo.UseSum ? counters.Sum() : counters.Max(); for (; j < data.NumberOfSerialTasks; j++) { - int c = await context.ScheduleTask(typeof(TestTask), new TestTaskData + int c = await context.ScheduleTask(activityInfo.ActivityType, new TestTaskData { - TaskId = "SerialTask" + (i + j).ToString(), - MaxDelayInMinutes = data.MaxDelayInMinutes, + TaskId = "SerialTask" + (i + j), + MaxDelay = maxDelayTimeSpan, }); - result = Math.Max(result, c); + result = activityInfo.UseSum ? result + c : Math.Max(result, c); } return result; } + + ActivityInformation GetActivityInfo(TestOrchestrationData data) + { + var activityTypeName = data.ActivityTypeName; + if (string.IsNullOrEmpty(activityTypeName)) + { + activityTypeName = typeof(TestTask).Name; + } + + ActivityInformation activityInfo; + if (!this._knownActivityTypes.TryGetValue(activityTypeName, out activityInfo)) + { + throw new InvalidOperationException("Unknown Activity Name"); + } + return activityInfo; + } + + class ActivityInformation + { + public ActivityInformation(Type activityType, bool useSum) + { + ActivityType = activityType; + UseSum = useSum; + } + + public Type ActivityType { get; } + + public bool UseSum { get; } + } } } diff --git a/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestrationData.cs b/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestrationData.cs index 64f15e27a..078fbf6c2 100644 --- a/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestrationData.cs +++ b/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestrationData.cs @@ -11,6 +11,7 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using System; using System.Runtime.Serialization; namespace DurableTask.Test.Orchestrations.Stress @@ -26,6 +27,12 @@ public class TestOrchestrationData public int NumberOfSerialTasks { get; set; } [DataMember] - public int MaxDelayInMinutes { get; set; } + public int MaxDelayTime { get; set; } + + [DataMember] + public string ActivityTypeName { get; set; } + + [DataMember] + public TimeSpan? DelayUnit { get; set; } //default value is TimeSpan.FromMinutes(1), this will be multiplied with MaxDelayTime to determine the wait time. } } diff --git a/Test/DurableTask.Test.Orchestrations/Stress/TestTask.cs b/Test/DurableTask.Test.Orchestrations/Stress/TestTask.cs index 78827ca58..63b77cbc5 100644 --- a/Test/DurableTask.Test.Orchestrations/Stress/TestTask.cs +++ b/Test/DurableTask.Test.Orchestrations/Stress/TestTask.cs @@ -30,12 +30,12 @@ protected override async Task ExecuteAsync(TaskContext context, TestTaskDat int c = Interlocked.Increment(ref this.counter); OrchestrationInstance instance = context.OrchestrationInstance; Random random = new Random(); - int minutesToSleep = random.Next(0, input.MaxDelayInMinutes); + int secondsToSleep = random.Next(0, (int)input.MaxDelay.TotalSeconds); - Console.WriteLine(string.Format("[InstanceId: {0}, ExecutionId: {1}, TaskId: {2}, Counter: {3}] ---> Sleeping for '{4}'", - instance.InstanceId, instance.ExecutionId, input.TaskId, c, minutesToSleep)); + Console.WriteLine(string.Format("[InstanceId: {0}, ExecutionId: {1}, TaskId: {2}, Counter: {3}] ---> Sleeping for '{4}' seconds", + instance.InstanceId, instance.ExecutionId, input.TaskId, c, secondsToSleep)); - await Task.Delay(TimeSpan.FromSeconds(minutesToSleep)); + await Task.Delay(TimeSpan.FromSeconds(secondsToSleep)); return c; } diff --git a/Test/DurableTask.Test.Orchestrations/Stress/TestTaskData.cs b/Test/DurableTask.Test.Orchestrations/Stress/TestTaskData.cs index 823b7bc9d..2df3a2a31 100644 --- a/Test/DurableTask.Test.Orchestrations/Stress/TestTaskData.cs +++ b/Test/DurableTask.Test.Orchestrations/Stress/TestTaskData.cs @@ -11,11 +11,13 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using System; + namespace DurableTask.Test.Orchestrations.Stress { public class TestTaskData { public string TaskId { get; set; } - public int MaxDelayInMinutes { get; set; } + public TimeSpan MaxDelay { get; set; } } } diff --git a/test/DurableTask.Stress.Tests/Program.cs b/test/DurableTask.Stress.Tests/Program.cs index cfdc3e2a8..04273a925 100644 --- a/test/DurableTask.Stress.Tests/Program.cs +++ b/test/DurableTask.Stress.Tests/Program.cs @@ -73,7 +73,7 @@ static void Main(string[] args) { NumberOfParallelTasks = int.Parse(ConfigurationManager.AppSettings["ChildOrchestrationParallelTasks"]), NumberOfSerialTasks = int.Parse(ConfigurationManager.AppSettings["ChildOrchestrationSerialTasks"]), - MaxDelayInMinutes = int.Parse(ConfigurationManager.AppSettings["TestTaskMaxDelayInMinutes"]), + MaxDelayTime = int.Parse(ConfigurationManager.AppSettings["TestTaskMaxDelayInMinutes"]), } }; From d43d796a3712ebce0cdb65413cb7efd3d70d0641 Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 087/210] Some more test changes and diagnostics. --- .../StressTests.cs | 1 - .../DurableTask.Test.Orchestrations.csproj | 1 + .../Stress/FixedTimeWaitingTask.cs | 1 - .../Stress/RandomTimeWaitingTask.cs | 28 +++++++++++++++++++ .../TestStatefulService.cs | 2 ++ .../FabricOrchestrationService.cs | 2 ++ .../ProviderEventSource.cs | 9 ++++++ 7 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 Test/DurableTask.Test.Orchestrations/Stress/RandomTimeWaitingTask.cs diff --git a/Test/DurableTask.ServiceFabric.Test/StressTests.cs b/Test/DurableTask.ServiceFabric.Test/StressTests.cs index e1af3c8ef..8ac7e3cc5 100644 --- a/Test/DurableTask.ServiceFabric.Test/StressTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/StressTests.cs @@ -25,7 +25,6 @@ namespace DurableTask.ServiceFabric.Test [TestClass] public class StressTests { - //Todo : Is it better to move this to a separate executable like service bus stress test? [TestMethod] public async Task ExecuteStressTest() { diff --git a/Test/DurableTask.Test.Orchestrations/DurableTask.Test.Orchestrations.csproj b/Test/DurableTask.Test.Orchestrations/DurableTask.Test.Orchestrations.csproj index a37a218ea..5eff56b2d 100644 --- a/Test/DurableTask.Test.Orchestrations/DurableTask.Test.Orchestrations.csproj +++ b/Test/DurableTask.Test.Orchestrations/DurableTask.Test.Orchestrations.csproj @@ -46,6 +46,7 @@ + diff --git a/Test/DurableTask.Test.Orchestrations/Stress/FixedTimeWaitingTask.cs b/Test/DurableTask.Test.Orchestrations/Stress/FixedTimeWaitingTask.cs index 6425608f4..600f86ff8 100644 --- a/Test/DurableTask.Test.Orchestrations/Stress/FixedTimeWaitingTask.cs +++ b/Test/DurableTask.Test.Orchestrations/Stress/FixedTimeWaitingTask.cs @@ -11,7 +11,6 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; using System.Threading.Tasks; namespace DurableTask.Test.Orchestrations.Stress diff --git a/Test/DurableTask.Test.Orchestrations/Stress/RandomTimeWaitingTask.cs b/Test/DurableTask.Test.Orchestrations/Stress/RandomTimeWaitingTask.cs new file mode 100644 index 000000000..40a62ddc7 --- /dev/null +++ b/Test/DurableTask.Test.Orchestrations/Stress/RandomTimeWaitingTask.cs @@ -0,0 +1,28 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Threading.Tasks; + +namespace DurableTask.Test.Orchestrations.Stress +{ + public sealed class RandomTimeWaitingTask : AsyncTaskActivity + { + protected override async Task ExecuteAsync(TaskContext context, TestTaskData input) + { + Random random = new Random(); + await Task.Delay(random.Next(50, 500)); + return 1; + } + } +} diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index c30e28189..e19c10292 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -182,6 +182,8 @@ Type GetOrchestrationType(string typeName) typeof(GetUserTask), typeof(GreetUserTask), typeof(GenerationBasicTask), + typeof(FixedTimeWaitingTask), + typeof(RandomTimeWaitingTask) }; } } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 1ef4adcde..d91e674ae 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -97,6 +97,7 @@ public bool IsMaxMessageCountExceeded(int currentMessageCount, OrchestrationRunt public int GetDelayInSecondsAfterOnProcessException(Exception exception) { + ProviderEventSource.Instance.LogException(exception.Message, exception.StackTrace); //Todo: Need to fine tune if (exception is TimeoutException) { @@ -108,6 +109,7 @@ public int GetDelayInSecondsAfterOnProcessException(Exception exception) public int GetDelayInSecondsAfterOnFetchException(Exception exception) { + ProviderEventSource.Instance.LogException(exception.Message, exception.StackTrace); //Todo: Need to fine tune if (exception is TimeoutException) { diff --git a/src/DurableTask.ServiceFabric/ProviderEventSource.cs b/src/DurableTask.ServiceFabric/ProviderEventSource.cs index 3f85c137a..b3651bf3b 100644 --- a/src/DurableTask.ServiceFabric/ProviderEventSource.cs +++ b/src/DurableTask.ServiceFabric/ProviderEventSource.cs @@ -55,5 +55,14 @@ public void LogOrchestrationFinished(string instanceId, string terminalStatus, d WriteEvent(2, instanceId, terminalStatus, runningTimeInSeconds, result); } } + + [Event(3, Level = EventLevel.Error, Message = "Exception : {0} With Stack Trace: {1}")] + public void LogException(string message, string stackTrace) + { + if (IsEnabled(EventLevel.Informational, Keywords.Orchestration)) + { + WriteEvent(3, message, stackTrace); + } + } } } From 91575db2392b519d60f6bc3a14106351de2054ed Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 088/210] Undoing some changes which were done for initial prototyping and no more required. --- src/DurableTask.Framework/IOrchestrationService.cs | 6 ------ .../ServiceBusOrchestrationService.cs | 8 +------- .../TaskActivityDispatcher.cs | 3 +-- .../TaskOrchestrationDispatcher.cs | 3 +-- src/DurableTask.Framework/WorkItemDispatcher.cs | 14 +++++--------- .../FabricOrchestrationService.cs | 2 -- .../Mocks/LocalOrchestrationService.cs | 2 -- 7 files changed, 8 insertions(+), 30 deletions(-) diff --git a/src/DurableTask.Framework/IOrchestrationService.cs b/src/DurableTask.Framework/IOrchestrationService.cs index e32e1d659..8787d9e9a 100644 --- a/src/DurableTask.Framework/IOrchestrationService.cs +++ b/src/DurableTask.Framework/IOrchestrationService.cs @@ -182,11 +182,5 @@ Task CompleteTaskOrchestrationWorkItemAsync( /// Abandons a single work item and releases the lock on it /// Task AbandonTaskActivityWorkItemAsync(TaskActivityWorkItem workItem); - - /// - /// When true, dispatcher waits for work item processing (for orchestrations and activities) - /// before it fetches the next work item. - /// - bool ProcessWorkItemSynchronously { get; } } } \ No newline at end of file diff --git a/src/DurableTask.Framework/ServiceBusOrchestrationService.cs b/src/DurableTask.Framework/ServiceBusOrchestrationService.cs index c6e458e3a..5475f0357 100644 --- a/src/DurableTask.Framework/ServiceBusOrchestrationService.cs +++ b/src/DurableTask.Framework/ServiceBusOrchestrationService.cs @@ -121,8 +121,7 @@ public ServiceBusOrchestrationService( "TrackingDispatcher", item => item == null ? string.Empty : item.InstanceId, this.FetchTrackingWorkItemAsync, - this.ProcessTrackingWorkItemAsync, - processWorkItemSynchronously: false) + this.ProcessTrackingWorkItemAsync) { GetDelayInSecondsAfterOnFetchException = GetDelayInSecondsAfterOnFetchException, GetDelayInSecondsAfterOnProcessException = GetDelayInSecondsAfterOnProcessException, @@ -906,11 +905,6 @@ public Task AbandonTaskActivityWorkItemAsync(TaskActivityWorkItem workItem) return message?.AbandonAsync(); } - /// - /// No need for synchronous processing as we have peek lock. - /// - public bool ProcessWorkItemSynchronously => false; - /// /// Create/start a new Orchestration /// diff --git a/src/DurableTask.Framework/TaskActivityDispatcher.cs b/src/DurableTask.Framework/TaskActivityDispatcher.cs index 9929d6725..b16d8ad5f 100644 --- a/src/DurableTask.Framework/TaskActivityDispatcher.cs +++ b/src/DurableTask.Framework/TaskActivityDispatcher.cs @@ -52,8 +52,7 @@ internal TaskActivityDispatcher( "TaskActivityDispatcher", item => item.Id, this.OnFetchWorkItemAsync, - this.OnProcessWorkItemAsync, - orchestrationService.ProcessWorkItemSynchronously) + this.OnProcessWorkItemAsync) { AbortWorkItem = orchestrationService.AbandonTaskActivityWorkItemAsync, GetDelayInSecondsAfterOnFetchException = orchestrationService.GetDelayInSecondsAfterOnFetchException, diff --git a/src/DurableTask.Framework/TaskOrchestrationDispatcher.cs b/src/DurableTask.Framework/TaskOrchestrationDispatcher.cs index 6dd1f51d9..4c929e0a8 100644 --- a/src/DurableTask.Framework/TaskOrchestrationDispatcher.cs +++ b/src/DurableTask.Framework/TaskOrchestrationDispatcher.cs @@ -57,8 +57,7 @@ internal TaskOrchestrationDispatcher( "TaskOrchestrationDispatcher", item => item == null ? string.Empty : item.InstanceId, this.OnFetchWorkItemAsync, - this.OnProcessWorkItemAsync, - orchestrationService.ProcessWorkItemSynchronously) + this.OnProcessWorkItemAsync) { GetDelayInSecondsAfterOnFetchException = orchestrationService.GetDelayInSecondsAfterOnFetchException, GetDelayInSecondsAfterOnProcessException = orchestrationService.GetDelayInSecondsAfterOnProcessException, diff --git a/src/DurableTask.Framework/WorkItemDispatcher.cs b/src/DurableTask.Framework/WorkItemDispatcher.cs index b5071f5dc..7a8d429c5 100644 --- a/src/DurableTask.Framework/WorkItemDispatcher.cs +++ b/src/DurableTask.Framework/WorkItemDispatcher.cs @@ -44,7 +44,6 @@ public class WorkItemDispatcher : IDisposable volatile int delayOverrideSecs; volatile int activeFetchers = 0; bool isStarted = false; - bool processWorkItemSynchronously; /// /// Gets or sets the maximum concurrent work items @@ -92,8 +91,7 @@ public WorkItemDispatcher( string name, Func workItemIdentifier, Func> fetchWorkItem, - Func processWorkItem, - bool processWorkItemSynchronously + Func processWorkItem ) { if (workItemIdentifier == null) @@ -116,7 +114,6 @@ bool processWorkItemSynchronously this.workItemIdentifier = workItemIdentifier; this.FetchWorkItem = fetchWorkItem; this.ProcessWorkItem = processWorkItem; - this.processWorkItemSynchronously = processWorkItemSynchronously; } /// @@ -262,11 +259,10 @@ async Task DispatchAsync(string dispatcherId) else { Interlocked.Increment(ref concurrentWorkItemCount); - var processTask = Task.Run(() => ProcessWorkItemAsync(context, workItem)); - if (this.processWorkItemSynchronously) - { - await processTask; //This makes the processing embrassingly sequential :-) - } + // We just want this to Run we intentionally don't wait + #pragma warning disable 4014 + Task.Run(() => ProcessWorkItemAsync(context, workItem)); + #pragma warning restore 4014 } } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index d91e674ae..60da207b0 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -246,8 +246,6 @@ public Task AbandonTaskActivityWorkItemAsync(TaskActivityWorkItem workItem) return this.activitiesProvider.AandonAsync(workItem.Id); } - public bool ProcessWorkItemSynchronously => false; - public Task RenewTaskActivityWorkItemLockAsync(TaskActivityWorkItem workItem) { return Task.FromResult(workItem); diff --git a/test/DurableTask.Framework.Tests/Mocks/LocalOrchestrationService.cs b/test/DurableTask.Framework.Tests/Mocks/LocalOrchestrationService.cs index 937fa6b4c..cd5d46197 100644 --- a/test/DurableTask.Framework.Tests/Mocks/LocalOrchestrationService.cs +++ b/test/DurableTask.Framework.Tests/Mocks/LocalOrchestrationService.cs @@ -509,8 +509,6 @@ public Task AbandonTaskActivityWorkItemAsync(TaskActivityWorkItem workItem) return Task.FromResult(null); } - public bool ProcessWorkItemSynchronously => false; - public Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workItem, TaskMessage responseMessage) { lock(this.thisLock) From c0e384eb355514f60c22ac49c923c0c96c5c1f08 Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 089/210] Changing the test structure again (this time favored duplication of test orchestration code than parameterizing it and reusing the code) --- .../Program.cs | 3 +- .../StressTests.cs | 11 ++-- .../DurableTask.Test.Orchestrations.csproj | 8 ++- .../Perf/DriverOrchestration.cs | 38 ++++++++++++ .../DriverOrchestrationData.cs} | 20 +++---- .../Perf/RandomTimeWaitingTask.cs | 40 +++++++++++++ .../RandomTimeWaitingTaskInput.cs} | 18 +++--- .../Perf/TestOrchestration.cs | 59 +++++++++++++++++++ .../Perf/TestOrchestrationData.cs | 38 ++++++++++++ .../Stress/DriverOrchestrationData.cs | 9 --- .../Stress/TestOrchestration.cs | 54 +++-------------- .../Stress/TestOrchestrationData.cs | 18 +----- .../Stress/TestTask.cs | 8 +-- .../Stress/TestTaskData.cs | 4 +- .../TestApplication.Common/IRemoteClient.cs | 2 +- .../TestStatefulService.cs | 27 +-------- test/DurableTask.Stress.Tests/Program.cs | 2 +- 17 files changed, 224 insertions(+), 135 deletions(-) create mode 100644 Test/DurableTask.Test.Orchestrations/Perf/DriverOrchestration.cs rename Test/DurableTask.Test.Orchestrations/{Stress/RandomTimeWaitingTask.cs => Perf/DriverOrchestrationData.cs} (65%) create mode 100644 Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTask.cs rename Test/DurableTask.Test.Orchestrations/{Stress/FixedTimeWaitingTask.cs => Perf/RandomTimeWaitingTaskInput.cs} (69%) create mode 100644 Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs create mode 100644 Test/DurableTask.Test.Orchestrations/Perf/TestOrchestrationData.cs diff --git a/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs b/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs index a0f7ff47d..c5afe6f1c 100644 --- a/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs +++ b/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs @@ -17,7 +17,7 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; -using DurableTask.Test.Orchestrations.Stress; +using DurableTask.Test.Orchestrations.Perf; using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; using TestApplication.Common; @@ -99,7 +99,6 @@ static async Task RunOrchestrations(CancellationToken cancellationToken) { NumberOfParallelTasks = 15, NumberOfSerialTasks = 5, - MaxDelayTime = 0 }; totalRequests++; diff --git a/Test/DurableTask.ServiceFabric.Test/StressTests.cs b/Test/DurableTask.ServiceFabric.Test/StressTests.cs index 8ac7e3cc5..72050704b 100644 --- a/Test/DurableTask.ServiceFabric.Test/StressTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/StressTests.cs @@ -14,7 +14,7 @@ using System; using System.Diagnostics; using System.Threading.Tasks; -using DurableTask.Test.Orchestrations.Stress; +using DurableTask.Test.Orchestrations.Perf; using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -32,13 +32,13 @@ public async Task ExecuteStressTest() var driverConfig = new DriverOrchestrationData() { - NumberOfIteration = 1, - NumberOfParallelTasks = 40, + NumberOfParallelOrchestrations = 40, SubOrchestrationData = new TestOrchestrationData() { NumberOfParallelTasks = 10, NumberOfSerialTasks = 5, - MaxDelayTime = 5, + MaxDelay = 5, + MinDelay = 0, DelayUnit = TimeSpan.FromSeconds(1) } }; @@ -59,8 +59,7 @@ public async Task ExecuteStressTest() Console.WriteLine($"Total Meastured Time: {elapsedTimeFormatter(totalTime)}"); Console.WriteLine($"Top level Orchestration Time: {elapsedTimeFormatter(orchestrationTime)}"); - var expectedResult = driverConfig.NumberOfIteration * driverConfig.NumberOfParallelTasks * - (driverConfig.SubOrchestrationData.NumberOfParallelTasks + driverConfig.SubOrchestrationData.NumberOfSerialTasks); + var expectedResult = driverConfig.NumberOfParallelOrchestrations * (driverConfig.SubOrchestrationData.NumberOfParallelTasks + driverConfig.SubOrchestrationData.NumberOfSerialTasks); Assert.AreEqual(expectedResult.ToString(), state.Output); } diff --git a/Test/DurableTask.Test.Orchestrations/DurableTask.Test.Orchestrations.csproj b/Test/DurableTask.Test.Orchestrations/DurableTask.Test.Orchestrations.csproj index 5eff56b2d..3389eef4f 100644 --- a/Test/DurableTask.Test.Orchestrations/DurableTask.Test.Orchestrations.csproj +++ b/Test/DurableTask.Test.Orchestrations/DurableTask.Test.Orchestrations.csproj @@ -42,11 +42,15 @@ + + + + + - - + diff --git a/Test/DurableTask.Test.Orchestrations/Perf/DriverOrchestration.cs b/Test/DurableTask.Test.Orchestrations/Perf/DriverOrchestration.cs new file mode 100644 index 000000000..00b41377b --- /dev/null +++ b/Test/DurableTask.Test.Orchestrations/Perf/DriverOrchestration.cs @@ -0,0 +1,38 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace DurableTask.Test.Orchestrations.Perf +{ + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + + public class DriverOrchestration : TaskOrchestration + { + public override async Task RunTask(OrchestrationContext context, DriverOrchestrationData data) + { + int result = 0; + List> results = new List>(); + int i = 0; + for (; i < data.NumberOfParallelOrchestrations; i++) + { + results.Add(context.CreateSubOrchestrationInstance(typeof(TestOrchestration), data.SubOrchestrationData)); + } + + int[] counters = await Task.WhenAll(results.ToArray()); + result = counters.Sum(); + + return result; + } + } +} diff --git a/Test/DurableTask.Test.Orchestrations/Stress/RandomTimeWaitingTask.cs b/Test/DurableTask.Test.Orchestrations/Perf/DriverOrchestrationData.cs similarity index 65% rename from Test/DurableTask.Test.Orchestrations/Stress/RandomTimeWaitingTask.cs rename to Test/DurableTask.Test.Orchestrations/Perf/DriverOrchestrationData.cs index 40a62ddc7..b77bab465 100644 --- a/Test/DurableTask.Test.Orchestrations/Stress/RandomTimeWaitingTask.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/DriverOrchestrationData.cs @@ -11,18 +11,18 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Threading.Tasks; +using System.Runtime.Serialization; -namespace DurableTask.Test.Orchestrations.Stress +namespace DurableTask.Test.Orchestrations.Perf { - public sealed class RandomTimeWaitingTask : AsyncTaskActivity + [DataContract] + [KnownType(typeof(DriverOrchestrationData))] + public class DriverOrchestrationData { - protected override async Task ExecuteAsync(TaskContext context, TestTaskData input) - { - Random random = new Random(); - await Task.Delay(random.Next(50, 500)); - return 1; - } + [DataMember] + public int NumberOfParallelOrchestrations { get; set; } + + [DataMember] + public TestOrchestrationData SubOrchestrationData { get; set; } } } diff --git a/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTask.cs b/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTask.cs new file mode 100644 index 000000000..e46a7a5b7 --- /dev/null +++ b/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTask.cs @@ -0,0 +1,40 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Threading.Tasks; + +namespace DurableTask.Test.Orchestrations.Perf +{ + public sealed class RandomTimeWaitingTask : AsyncTaskActivity + { + protected override async Task ExecuteAsync(TaskContext context, RandomTimeWaitingTaskInput input) + { + int delayTime; + + if (input.MaxDelay == input.MinDelay) + { + delayTime = input.MaxDelay; + } + else + { + Random random = new Random(); + delayTime = random.Next(input.MinDelay, input.MaxDelay); + } + + await Task.Delay(TimeSpan.FromMilliseconds(input.DelayUnit.TotalMilliseconds * delayTime)); + + return 1; + } + } +} diff --git a/Test/DurableTask.Test.Orchestrations/Stress/FixedTimeWaitingTask.cs b/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTaskInput.cs similarity index 69% rename from Test/DurableTask.Test.Orchestrations/Stress/FixedTimeWaitingTask.cs rename to Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTaskInput.cs index 600f86ff8..872722c91 100644 --- a/Test/DurableTask.Test.Orchestrations/Stress/FixedTimeWaitingTask.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTaskInput.cs @@ -11,16 +11,18 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System.Threading.Tasks; +using System; -namespace DurableTask.Test.Orchestrations.Stress +namespace DurableTask.Test.Orchestrations.Perf { - public sealed class FixedTimeWaitingTask : AsyncTaskActivity + public class RandomTimeWaitingTaskInput { - protected override async Task ExecuteAsync(TaskContext context, TestTaskData input) - { - await Task.Delay(input.MaxDelay); - return 1; - } + public string TaskId { get; set; } + + public int MaxDelay { get; set; } + + public int MinDelay { get; set; } + + public TimeSpan DelayUnit { get; set; } } } diff --git a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs new file mode 100644 index 000000000..45e279f25 --- /dev/null +++ b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs @@ -0,0 +1,59 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace DurableTask.Test.Orchestrations.Perf +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using DurableTask; + + public class TestOrchestration : TaskOrchestration + { + public override async Task RunTask(OrchestrationContext context, TestOrchestrationData data) + { + int result = 0; + List> results = new List>(); + int i = 0; + int j = 0; + for (; i < data.NumberOfParallelTasks; i++) + { + results.Add(context.ScheduleTask(typeof(RandomTimeWaitingTask), new RandomTimeWaitingTaskInput + { + TaskId = "ParallelTask: " + i.ToString(), + MaxDelay = data.MaxDelay, + MinDelay = data.MinDelay, + DelayUnit = data.DelayUnit + })); + } + + int[] counters = await Task.WhenAll(results.ToArray()); + result = counters.Sum(); + + for (; j < data.NumberOfSerialTasks; j++) + { + int c = await context.ScheduleTask(typeof(RandomTimeWaitingTask), new RandomTimeWaitingTaskInput + { + TaskId = "SerialTask" + (i + j).ToString(), + MaxDelay = data.MaxDelay, + MinDelay = data.MinDelay, + DelayUnit = data.DelayUnit + }); + result += c; + } + + return result; + } + } +} diff --git a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestrationData.cs b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestrationData.cs new file mode 100644 index 000000000..dbe80847b --- /dev/null +++ b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestrationData.cs @@ -0,0 +1,38 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Runtime.Serialization; + +namespace DurableTask.Test.Orchestrations.Perf +{ + [DataContract] + [KnownType(typeof(TestOrchestrationData))] + public class TestOrchestrationData + { + [DataMember] + public int NumberOfParallelTasks { get; set; } + + [DataMember] + public int NumberOfSerialTasks { get; set; } + + [DataMember] + public int MaxDelay { get; set; } + + [DataMember] + public int MinDelay { get; set; } + + [DataMember] + public TimeSpan DelayUnit { get; set; } + } +} diff --git a/Test/DurableTask.Test.Orchestrations/Stress/DriverOrchestrationData.cs b/Test/DurableTask.Test.Orchestrations/Stress/DriverOrchestrationData.cs index f9670bb69..62f237e6b 100644 --- a/Test/DurableTask.Test.Orchestrations/Stress/DriverOrchestrationData.cs +++ b/Test/DurableTask.Test.Orchestrations/Stress/DriverOrchestrationData.cs @@ -11,21 +11,12 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System.Runtime.Serialization; - namespace DurableTask.Test.Orchestrations.Stress { - [DataContract] - [KnownType(typeof(DriverOrchestrationData))] public class DriverOrchestrationData { - [DataMember] public int NumberOfParallelTasks { get; set; } - - [DataMember] public int NumberOfIteration { get; set; } - - [DataMember] public TestOrchestrationData SubOrchestrationData { get; set; } } } diff --git a/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestration.cs b/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestration.cs index 1d939e317..882fa785d 100644 --- a/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestration.cs +++ b/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestration.cs @@ -21,73 +21,35 @@ namespace DurableTask.Test.Orchestrations.Stress public class TestOrchestration : TaskOrchestration { - readonly Dictionary _knownActivityTypes = new Dictionary() - { - {typeof(TestTask).Name, new ActivityInformation(typeof(TestTask), false) }, - {typeof(FixedTimeWaitingTask).Name, new ActivityInformation(typeof(FixedTimeWaitingTask), true) }, - }; - public override async Task RunTask(OrchestrationContext context, TestOrchestrationData data) { - var activityInfo = GetActivityInfo(data); - var maxDelayTimeSpan = TimeSpan.FromMilliseconds((data.DelayUnit ?? TimeSpan.FromMinutes(1)).TotalMilliseconds * data.MaxDelayTime); - int result = 0; List> results = new List>(); int i = 0; int j = 0; for (; i < data.NumberOfParallelTasks; i++) { - results.Add(context.ScheduleTask(activityInfo.ActivityType, new TestTaskData + results.Add(context.ScheduleTask(typeof(TestTask), new TestTaskData { - TaskId = "ParallelTask: " + i, - MaxDelay = maxDelayTimeSpan, + TaskId = "ParallelTask: " + i.ToString(), + MaxDelayInMinutes = data.MaxDelayInMinutes, })); } int[] counters = await Task.WhenAll(results.ToArray()); - result = activityInfo.UseSum ? counters.Sum() : counters.Max(); + result = counters.Max(); for (; j < data.NumberOfSerialTasks; j++) { - int c = await context.ScheduleTask(activityInfo.ActivityType, new TestTaskData + int c = await context.ScheduleTask(typeof(TestTask), new TestTaskData { - TaskId = "SerialTask" + (i + j), - MaxDelay = maxDelayTimeSpan, + TaskId = "SerialTask" + (i + j).ToString(), + MaxDelayInMinutes = data.MaxDelayInMinutes, }); - result = activityInfo.UseSum ? result + c : Math.Max(result, c); + result = Math.Max(result, c); } return result; } - - ActivityInformation GetActivityInfo(TestOrchestrationData data) - { - var activityTypeName = data.ActivityTypeName; - if (string.IsNullOrEmpty(activityTypeName)) - { - activityTypeName = typeof(TestTask).Name; - } - - ActivityInformation activityInfo; - if (!this._knownActivityTypes.TryGetValue(activityTypeName, out activityInfo)) - { - throw new InvalidOperationException("Unknown Activity Name"); - } - return activityInfo; - } - - class ActivityInformation - { - public ActivityInformation(Type activityType, bool useSum) - { - ActivityType = activityType; - UseSum = useSum; - } - - public Type ActivityType { get; } - - public bool UseSum { get; } - } } } diff --git a/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestrationData.cs b/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestrationData.cs index 078fbf6c2..97a0fea2b 100644 --- a/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestrationData.cs +++ b/Test/DurableTask.Test.Orchestrations/Stress/TestOrchestrationData.cs @@ -11,28 +11,12 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Runtime.Serialization; - namespace DurableTask.Test.Orchestrations.Stress { - [DataContract] - [KnownType(typeof(TestOrchestrationData))] public class TestOrchestrationData { - [DataMember] public int NumberOfParallelTasks { get; set; } - - [DataMember] public int NumberOfSerialTasks { get; set; } - - [DataMember] - public int MaxDelayTime { get; set; } - - [DataMember] - public string ActivityTypeName { get; set; } - - [DataMember] - public TimeSpan? DelayUnit { get; set; } //default value is TimeSpan.FromMinutes(1), this will be multiplied with MaxDelayTime to determine the wait time. + public int MaxDelayInMinutes { get; set; } } } diff --git a/Test/DurableTask.Test.Orchestrations/Stress/TestTask.cs b/Test/DurableTask.Test.Orchestrations/Stress/TestTask.cs index 63b77cbc5..65b1ec645 100644 --- a/Test/DurableTask.Test.Orchestrations/Stress/TestTask.cs +++ b/Test/DurableTask.Test.Orchestrations/Stress/TestTask.cs @@ -30,12 +30,12 @@ protected override async Task ExecuteAsync(TaskContext context, TestTaskDat int c = Interlocked.Increment(ref this.counter); OrchestrationInstance instance = context.OrchestrationInstance; Random random = new Random(); - int secondsToSleep = random.Next(0, (int)input.MaxDelay.TotalSeconds); + int minutesToSleep = random.Next(0, input.MaxDelayInMinutes); - Console.WriteLine(string.Format("[InstanceId: {0}, ExecutionId: {1}, TaskId: {2}, Counter: {3}] ---> Sleeping for '{4}' seconds", - instance.InstanceId, instance.ExecutionId, input.TaskId, c, secondsToSleep)); + Console.WriteLine(string.Format("[InstanceId: {0}, ExecutionId: {1}, TaskId: {2}, Counter: {3}] ---> Sleeping for '{4}'", + instance.InstanceId, instance.ExecutionId, input.TaskId, c, minutesToSleep)); - await Task.Delay(TimeSpan.FromSeconds(secondsToSleep)); + await Task.Delay(TimeSpan.FromMinutes(minutesToSleep)); return c; } diff --git a/Test/DurableTask.Test.Orchestrations/Stress/TestTaskData.cs b/Test/DurableTask.Test.Orchestrations/Stress/TestTaskData.cs index 2df3a2a31..823b7bc9d 100644 --- a/Test/DurableTask.Test.Orchestrations/Stress/TestTaskData.cs +++ b/Test/DurableTask.Test.Orchestrations/Stress/TestTaskData.cs @@ -11,13 +11,11 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; - namespace DurableTask.Test.Orchestrations.Stress { public class TestTaskData { public string TaskId { get; set; } - public TimeSpan MaxDelay { get; set; } + public int MaxDelayInMinutes { get; set; } } } diff --git a/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs b/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs index 4c1f3468c..6f75f4fd8 100644 --- a/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs +++ b/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs @@ -14,7 +14,7 @@ using System; using System.Threading.Tasks; using DurableTask; -using DurableTask.Test.Orchestrations.Stress; +using DurableTask.Test.Orchestrations.Perf; using Microsoft.ServiceFabric.Services.Remoting; namespace TestApplication.Common diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index e19c10292..ad53dd7df 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -19,13 +19,13 @@ using System.Threading.Tasks; using DurableTask; using DurableTask.ServiceFabric; +using DurableTask.Test.Orchestrations.Perf; using Microsoft.ServiceFabric.Services.Communication.Runtime; using Microsoft.ServiceFabric.Services.Runtime; using TestApplication.Common; using TestStatefulService.DebugHelper; using TestStatefulService.TestOrchestrations; using Microsoft.ServiceFabric.Services.Remoting.Runtime; -using DurableTask.Test.Orchestrations.Stress; namespace TestStatefulService { @@ -38,7 +38,6 @@ internal sealed class TestStatefulService : StatefulService, IRemoteClient TaskHubClient client; ReplicaRole currentRole; TestExecutor testExecutor; - TestTask testTask; object syncLock = new object(); public TestStatefulService(StatefulServiceContext context) @@ -74,12 +73,9 @@ protected override IEnumerable CreateServiceReplicaListe /// Canceled when Service Fabric needs to shut down this service replica. protected override async Task RunAsync(CancellationToken cancellationToken) { - SafeCreateTestTask(); - await this.worker .AddTaskOrchestrations(KnownOrchestrationTypeNames.Values.ToArray()) .AddTaskActivities(KnownActivities) - .AddTaskActivities(testTask) .StartAsync(); //await this.testExecutor.StartAsync(); @@ -103,12 +99,6 @@ public async Task RunOrchestrationAsync(string orchestration public async Task RunDriverOrchestrationAsync(DriverOrchestrationData input, TimeSpan waitTimeout) { - SafeCreateTestTask(); - // This was done to be able to deploy the test app once and run the stress test sequentially and repeatedly - // (faster) and assert the result for different combination of parameter values in the input. - // Catch is that if there are 2 simultaneous top level orchestration instances running in parallel, - // the result is unpredictable and cannot be verified though. - this.testTask.counter = 0; return await this.RunOrchestrationAsync(typeof(DriverOrchestration).Name, input, waitTimeout); } @@ -143,20 +133,6 @@ public Task PurgeOrchestrationHistoryEventsAsync() return this.client.PurgeOrchestrationInstanceHistoryAsync(DateTime.UtcNow, OrchestrationStateTimeRangeFilterType.OrchestrationCompletedTimeFilter); } - void SafeCreateTestTask() - { - if (this.testTask == null) - { - lock (this.syncLock) - { - if (this.testTask == null) - { - this.testTask = new TestTask(); - } - } - } - } - Type GetOrchestrationType(string typeName) { if (!KnownOrchestrationTypeNames.ContainsKey(typeName)) @@ -182,7 +158,6 @@ Type GetOrchestrationType(string typeName) typeof(GetUserTask), typeof(GreetUserTask), typeof(GenerationBasicTask), - typeof(FixedTimeWaitingTask), typeof(RandomTimeWaitingTask) }; } diff --git a/test/DurableTask.Stress.Tests/Program.cs b/test/DurableTask.Stress.Tests/Program.cs index 04273a925..cfdc3e2a8 100644 --- a/test/DurableTask.Stress.Tests/Program.cs +++ b/test/DurableTask.Stress.Tests/Program.cs @@ -73,7 +73,7 @@ static void Main(string[] args) { NumberOfParallelTasks = int.Parse(ConfigurationManager.AppSettings["ChildOrchestrationParallelTasks"]), NumberOfSerialTasks = int.Parse(ConfigurationManager.AppSettings["ChildOrchestrationSerialTasks"]), - MaxDelayTime = int.Parse(ConfigurationManager.AppSettings["TestTaskMaxDelayInMinutes"]), + MaxDelayInMinutes = int.Parse(ConfigurationManager.AppSettings["TestTaskMaxDelayInMinutes"]), } }; From b3aac23c2e4f739576a49244b81bfec3cc74ee5f Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 090/210] Reverting another change made to the core provider. --- src/DurableTask.Framework/Common/Utils.cs | 5 +-- .../DurableTask.ServiceFabric.csproj | 1 + src/DurableTask.ServiceFabric/Utils.cs | 41 +++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 src/DurableTask.ServiceFabric/Utils.cs diff --git a/src/DurableTask.Framework/Common/Utils.cs b/src/DurableTask.Framework/Common/Utils.cs index 2e4b6c17f..16f50737c 100644 --- a/src/DurableTask.Framework/Common/Utils.cs +++ b/src/DurableTask.Framework/Common/Utils.cs @@ -25,10 +25,7 @@ namespace DurableTask.Common using DurableTask.Serializing; using Tracing; - /// - /// Utilities. - /// - public static class Utils + internal static class Utils { const int FullGzipHeaderLength = 10; diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index db672dff6..51fe27557 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -89,6 +89,7 @@ + diff --git a/src/DurableTask.ServiceFabric/Utils.cs b/src/DurableTask.ServiceFabric/Utils.cs new file mode 100644 index 000000000..b97350f29 --- /dev/null +++ b/src/DurableTask.ServiceFabric/Utils.cs @@ -0,0 +1,41 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; + +namespace DurableTask.ServiceFabric +{ + internal static class Utils + { + public static OrchestrationState BuildOrchestrationState(OrchestrationRuntimeState runtimeState) + { + return new OrchestrationState + { + OrchestrationInstance = runtimeState.OrchestrationInstance, + ParentInstance = runtimeState.ParentInstance, + Name = runtimeState.Name, + Version = runtimeState.Version, + Status = runtimeState.Status, + Tags = runtimeState.Tags, + OrchestrationStatus = runtimeState.OrchestrationStatus, + CreatedTime = runtimeState.CreatedTime, + CompletedTime = runtimeState.CompletedTime, + LastUpdatedTime = DateTime.UtcNow, + Size = runtimeState.Size, + CompressedSize = runtimeState.CompressedSize, + Input = runtimeState.Input, + Output = runtimeState.Output + }; + } + } +} From 5039543b9174e998151496cc9721075bef121d51 Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 091/210] Adding simple perf test (using preditable sleep time). --- .../StressTests.cs | 66 ++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.Test/StressTests.cs b/Test/DurableTask.ServiceFabric.Test/StressTests.cs index 72050704b..ec0b396e4 100644 --- a/Test/DurableTask.ServiceFabric.Test/StressTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/StressTests.cs @@ -12,6 +12,7 @@ // ---------------------------------------------------------------------------------- using System; +using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; using DurableTask.Test.Orchestrations.Perf; @@ -28,8 +29,6 @@ public class StressTests [TestMethod] public async Task ExecuteStressTest() { - var serviceClient = ServiceProxy.Create(new Uri("fabric:/TestFabricApplicationType/TestStatefulService"), new ServicePartitionKey(1)); - var driverConfig = new DriverOrchestrationData() { NumberOfParallelOrchestrations = 40, @@ -43,6 +42,27 @@ public async Task ExecuteStressTest() } }; + await RunDriverOrchestrationHelper(driverConfig); + } + + [TestMethod] + public async Task SimplePerformanceExperiment() + { + var testOrchestratorInput = new TestOrchestrationData() + { + NumberOfParallelTasks = 0, + NumberOfSerialTasks = 3, + MaxDelay = 3, + MinDelay = 3, + DelayUnit = TimeSpan.FromSeconds(1) + }; + + await RunTestOrchestrationsHelper(100, testOrchestratorInput); + } + + async Task RunDriverOrchestrationHelper(DriverOrchestrationData driverConfig) + { + var serviceClient = ServiceProxy.Create(new Uri("fabric:/TestFabricApplicationType/TestStatefulService"), new ServicePartitionKey(1)); Console.WriteLine($"Orchestration getting scheduled: {DateTime.Now}"); Stopwatch stopWatch = Stopwatch.StartNew(); @@ -63,5 +83,47 @@ public async Task ExecuteStressTest() Assert.AreEqual(expectedResult.ToString(), state.Output); } + + async Task RunTestOrchestrationsHelper(int numberOfInstances, TestOrchestrationData orchestrationInput) + { + var serviceClient = ServiceProxy.Create(new Uri("fabric:/TestFabricApplicationType/TestStatefulService"), new ServicePartitionKey(1)); + + List> waitTasks = new List>(); + Stopwatch stopWatch = Stopwatch.StartNew(); + for (int i = 0; i < numberOfInstances; i++) + { + var instance = await serviceClient.StartTestOrchestrationAsync(orchestrationInput); + var waitTask = serviceClient.WaitForOrchestration(instance, TimeSpan.FromMinutes(2)); + waitTasks.Add(waitTask); + } + + var outcomes = await Task.WhenAll(waitTasks); + stopWatch.Stop(); + + Func elapsedTimeFormatter = timeSpan => $"{timeSpan.Hours:00}:{timeSpan.Minutes:00}:{timeSpan.Seconds:00}.{timeSpan.Milliseconds / 10:00}"; + Console.WriteLine($"Total Meastured Time For All Orchestrations: {elapsedTimeFormatter(stopWatch.Elapsed)}"); + + var expectedResult = (orchestrationInput.NumberOfParallelTasks + orchestrationInput.NumberOfSerialTasks).ToString(); + TimeSpan minTime = TimeSpan.MaxValue; + TimeSpan maxTime = TimeSpan.FromMilliseconds(0); + + foreach (var outcome in outcomes) + { + Assert.IsNotNull(outcome); + Assert.AreEqual(expectedResult, outcome.Output); + TimeSpan orchestrationTime = outcome.CompletedTime - outcome.CreatedTime; + if (minTime > orchestrationTime) + { + minTime = orchestrationTime; + } + if (maxTime < orchestrationTime) + { + maxTime = orchestrationTime; + } + } + + Console.WriteLine($"Minimum time taken for any orchestration instance : {elapsedTimeFormatter(minTime)}"); + Console.WriteLine($"Maximum time taken for any orchestration instance : {elapsedTimeFormatter(maxTime)}"); + } } } From 9d97bb01f3961ba094e1482a8c8e1b66e9765945 Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 092/210] More test scenarios. --- .../StressTests.cs | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/Test/DurableTask.ServiceFabric.Test/StressTests.cs b/Test/DurableTask.ServiceFabric.Test/StressTests.cs index ec0b396e4..ecc61aa32 100644 --- a/Test/DurableTask.ServiceFabric.Test/StressTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/StressTests.cs @@ -60,6 +60,35 @@ public async Task SimplePerformanceExperiment() await RunTestOrchestrationsHelper(100, testOrchestratorInput); } + [TestMethod] + public async Task RunThousandOrchsWithHundredMilliSecondDelayInBetweenStartingEach() + { + var testOrchestratorInput = new TestOrchestrationData() + { + NumberOfParallelTasks = 16, + NumberOfSerialTasks = 4, + MaxDelay = 500, + MinDelay = 50, + DelayUnit = TimeSpan.FromMilliseconds(1) + }; + + await RunTestOrchestrationsHelper(1000, testOrchestratorInput, delayGeneratorFunction: (totalRequestsSoFar) => TimeSpan.FromMilliseconds(100)); + } + + [TestMethod] + public async Task InfrequentLoadScenario() + { + var testOrchestratorInput = new TestOrchestrationData() + { + NumberOfParallelTasks = 0, + NumberOfSerialTasks = 2, + MaxDelay = 0, + MinDelay = 0, + }; + + await RunTestOrchestrationsHelper(200, testOrchestratorInput, delayGeneratorFunction: (totalRequestsSoFar) => TimeSpan.FromSeconds(1)); + } + async Task RunDriverOrchestrationHelper(DriverOrchestrationData driverConfig) { var serviceClient = ServiceProxy.Create(new Uri("fabric:/TestFabricApplicationType/TestStatefulService"), new ServicePartitionKey(1)); @@ -84,7 +113,7 @@ async Task RunDriverOrchestrationHelper(DriverOrchestrationData driverConfig) Assert.AreEqual(expectedResult.ToString(), state.Output); } - async Task RunTestOrchestrationsHelper(int numberOfInstances, TestOrchestrationData orchestrationInput) + async Task RunTestOrchestrationsHelper(int numberOfInstances, TestOrchestrationData orchestrationInput, Func delayGeneratorFunction = null) { var serviceClient = ServiceProxy.Create(new Uri("fabric:/TestFabricApplicationType/TestStatefulService"), new ServicePartitionKey(1)); @@ -95,6 +124,10 @@ async Task RunTestOrchestrationsHelper(int numberOfInstances, TestOrchestrationD var instance = await serviceClient.StartTestOrchestrationAsync(orchestrationInput); var waitTask = serviceClient.WaitForOrchestration(instance, TimeSpan.FromMinutes(2)); waitTasks.Add(waitTask); + if (delayGeneratorFunction != null) + { + await Task.Delay(delayGeneratorFunction(i)); + } } var outcomes = await Task.WhenAll(waitTasks); From ab685318e1d3044d9a049f3a53d71b8eb4fe6998 Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 093/210] Clearing a Todo : Use signalling between Send and Receive instead of polling. --- .../AsyncManualResetEvent.cs | 54 +++++++++++++++++ .../DurableTask.ServiceFabric.csproj | 1 + .../PeekLockQueue.cs | 60 ++++++++++++++----- 3 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs diff --git a/src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs b/src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs new file mode 100644 index 000000000..aa76d25a6 --- /dev/null +++ b/src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs @@ -0,0 +1,54 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace DurableTask.ServiceFabric +{ + using System; + using System.Threading; + using System.Threading.Tasks; + + public sealed class AsyncManualResetEvent + { + TaskCompletionSource tcs; + + public AsyncManualResetEvent() + { + this.tcs = new TaskCompletionSource(); + } + + public async Task WaitAsync(TimeSpan timeout, CancellationToken cancellationToken) + { + var delayTask = Task.Delay(timeout, cancellationToken); + var resultTask = await Task.WhenAny(delayTask, this.tcs.Task); + return delayTask != resultTask; + } + + public void Set() + { + this.tcs.TrySetResult(true); + } + + public void Reset() + { + while (true) + { + var thisTcs = this.tcs; + + if (!thisTcs.Task.IsCompleted || Interlocked.CompareExchange(ref this.tcs, new TaskCompletionSource(), thisTcs) == thisTcs) + { + return; + } + } + } + } +} diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 51fe27557..79783d216 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -73,6 +73,7 @@ + diff --git a/src/DurableTask.ServiceFabric/PeekLockQueue.cs b/src/DurableTask.ServiceFabric/PeekLockQueue.cs index 833316fa8..f9457a0a5 100644 --- a/src/DurableTask.ServiceFabric/PeekLockQueue.cs +++ b/src/DurableTask.ServiceFabric/PeekLockQueue.cs @@ -16,7 +16,6 @@ namespace DurableTask.ServiceFabric using System; using System.Collections.Concurrent; using System.Collections.Generic; - using System.Diagnostics; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; @@ -30,7 +29,9 @@ class PeekLockQueue where TKey : IComparable, IEquatable store; - ConcurrentQueue inMemoryQueue = new ConcurrentQueue(); + readonly ConcurrentQueue inMemoryQueue = new ConcurrentQueue(); + + readonly AsyncManualResetEvent waitEvent = new AsyncManualResetEvent(); public PeekLockQueue(IReliableStateManager stateManager, string storeName) { @@ -69,31 +70,44 @@ public Task StopAsync() public async Task> ReceiveAsync(TimeSpan receiveTimeout) { - Stopwatch timer = Stopwatch.StartNew(); - while (timer.Elapsed < receiveTimeout && !this.cancellationTokenSource.IsCancellationRequested) + ThrowIfStopped(); + + TKey key; + bool newItemsBeforeTimeout = true; + while (newItemsBeforeTimeout) { - TKey key; if (this.inMemoryQueue.TryDequeue(out key)) { - using (var txn = this.stateManager.CreateTransaction()) + try { - var result = await this.store.TryGetValueAsync(txn, key); - if (result.HasValue) + using (var txn = this.stateManager.CreateTransaction()) { - return new Message(key, result.Value); + var result = await this.store.TryGetValueAsync(txn, key); + if (result.HasValue) + { + return new Message(key, result.Value); + } + throw new Exception("Internal server error : Unexpectedly ended up not having an item in dictionary while having the item key in memory"); } - throw new Exception("Internal server error"); + } + catch (TimeoutException) + { + this.inMemoryQueue.Enqueue(key); + throw; } } - //Todo : Can use a signal mechanism between send and receive - await Task.Delay(100, this.cancellationTokenSource.Token); + this.waitEvent.Reset(); + newItemsBeforeTimeout = await this.waitEvent.WaitAsync(receiveTimeout, this.cancellationTokenSource.Token); } + return null; } public Task CompleteAsync(ITransaction tx, TKey key) { + ThrowIfStopped(); + return this.store.TryRemoveAsync(tx, key); } @@ -103,12 +117,17 @@ public Task CompleteAsync(ITransaction tx, TKey key) /// public Task SendBeginAsync(ITransaction tx, Message item) { + ThrowIfStopped(); + return this.store.TryAddAsync(tx, item.Key, item.Value); } public void SendComplete(Message item) { + ThrowIfStopped(); + this.inMemoryQueue.Enqueue(item.Key); + this.waitEvent.Set(); } /// @@ -117,25 +136,38 @@ public void SendComplete(Message item) /// public async Task SendBatchBeginAsync(ITransaction tx, IEnumerable> items) { + ThrowIfStopped(); + foreach (var item in items) { - await this.SendBeginAsync(tx, item); + await this.store.TryAddAsync(tx, item.Key, item.Value); } } public void SendBatchComplete(IEnumerable> items) { + ThrowIfStopped(); + foreach (var item in items) { - this.SendComplete(item); + this.inMemoryQueue.Enqueue(item.Key); } + this.waitEvent.Set(); } public Task AandonAsync(TKey key) { + ThrowIfStopped(); + this.inMemoryQueue.Enqueue(key); + this.waitEvent.Set(); return Task.FromResult(null); } + + void ThrowIfStopped() + { + this.cancellationTokenSource.Token.ThrowIfCancellationRequested(); + } } [DataContract] From 0216156f23bdb2ef08e6057c360dfb36e67ab75f Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 094/210] Some attempt to use inmemory locking for sessions. (And avoid enumerating the dictionary each time when session queue is empty). Need to actually run perf to see if it improves. --- .../PersistentSessionTests.cs | 3 +- .../FabricOrchestrationService.cs | 14 +- .../FabricOrchestrationServiceClient.cs | 9 +- .../PersistentSession.api.cs | 14 +- .../PersistentSession.cs | 9 +- .../SessionsProvider.cs | 141 ++++++++++++++---- 6 files changed, 135 insertions(+), 55 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs index abff13fdc..a1c94f645 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs @@ -53,7 +53,7 @@ public void SerializationTest() } PersistentSession testSession = PersistentSession.Create("testSession", events.ToImmutableList(), - messages.ToImmutableList(), scheduledMessages.ToImmutableList(), isLocked: true); + messages.ToImmutableList(), scheduledMessages.ToImmutableList()); using (var stream = new MemoryStream()) { @@ -71,7 +71,6 @@ public void SerializationTest() Assert.IsNotNull(deserialized); Assert.AreEqual("testSession", deserialized.SessionId); - Assert.IsFalse(deserialized.IsLocked); Assert.AreEqual(numberOfItemsInCollections*2 + 2, deserialized.SessionState.Count); Assert.AreEqual(numberOfItemsInCollections, deserialized.Messages.Count); Assert.AreEqual(numberOfItemsInCollections, deserialized.ScheduledMessages.Count); diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 60da207b0..d12cc6d4c 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -165,7 +165,7 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( var activityMessages = outboundMessages.Select(m => new Message(Guid.NewGuid().ToString(), m)).ToList(); await this.activitiesProvider.SendBatchBeginAsync(txn, activityMessages); - await this.orchestrationProvider.CompleteAndUpdateSession(txn, workItem.InstanceId, newOrchestrationRuntimeState, timerMessages); + var newSessionValue = await this.orchestrationProvider.CompleteAndUpdateSession(txn, workItem.InstanceId, newOrchestrationRuntimeState, timerMessages); if (orchestratorMessages?.Count > 0) { @@ -184,13 +184,22 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( } await txn.CommitAsync(); + this.activitiesProvider.SendBatchComplete(activityMessages); + this.orchestrationProvider.TryUnlockSession(workItem.InstanceId, putBackInQueue: newSessionValue.Messages.Any()); + if (orchestratorMessages != null) + { + foreach (var subOrchMessage in orchestratorMessages) + { + this.orchestrationProvider.TryEnqueueSession(subOrchMessage.OrchestrationInstance.InstanceId); + } + } } } public Task AbandonTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkItem workItem) { - //Todo: Implement to unlock session + this.orchestrationProvider.TryUnlockSession(workItem.InstanceId, putBackInQueue: true); return Task.FromResult(null); } @@ -238,6 +247,7 @@ public async Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workIte await this.activitiesProvider.CompleteAsync(txn, workItem.Id); await this.orchestrationProvider.AppendMessageAsync(txn, responseMessage); await txn.CommitAsync(); + this.orchestrationProvider.TryEnqueueSession(responseMessage.OrchestrationInstance.InstanceId); } } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index 6c3ed2159..3ca9323d9 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -52,13 +52,9 @@ public async Task CreateTaskOrchestrationAsync(TaskMessage creationMessage) ProviderEventSource.Instance.LogOrchestrationCreated(instance.InstanceId); } - public async Task SendTaskOrchestrationMessageAsync(TaskMessage message) + public Task SendTaskOrchestrationMessageAsync(TaskMessage message) { - using (var txn = this.stateManager.CreateTransaction()) - { - await this.orchestrationProvider.AppendMessageAsync(txn, message); - await txn.CommitAsync(); - } + return this.orchestrationProvider.AppendMessageAsync(message); } public async Task ForceTerminateTaskOrchestrationAsync(string instanceId, string reason) @@ -101,6 +97,7 @@ public Task PurgeOrchestrationHistoryAsync(DateTime thresholdDateTimeUtc, Orches return this.instanceStore.PurgeOrchestrationHistoryEventsAsync(thresholdDateTimeUtc); } + //Todo: Timeout logic seems to be broken, don't know why, need to investigate. public async Task WaitForOrchestrationAsync(string instanceId, string executionId, TimeSpan timeout, CancellationToken cancellationToken) { ThrowIfInstanceStoreNotConfigured(); diff --git a/src/DurableTask.ServiceFabric/PersistentSession.api.cs b/src/DurableTask.ServiceFabric/PersistentSession.api.cs index be840c62e..4dd30a126 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.api.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.api.cs @@ -53,7 +53,7 @@ public PersistentSession FireScheduledMessages() if (changed) { - return Create(this.SessionId, this.SessionState, messagesBuilder.ToImmutableList(), remainingScheduledMessagesBuilder.ToImmutableList(), this.IsLocked); + return Create(this.SessionId, this.SessionState, messagesBuilder.ToImmutableList(), remainingScheduledMessagesBuilder.ToImmutableList()); } return this; @@ -62,7 +62,7 @@ public PersistentSession FireScheduledMessages() public PersistentSession ReceiveMessages() { var newMessages = this.Messages.ToBuilder().ConvertAll(m => ReceivableTaskMessage.Create(m.TaskMessage, isReceived: true)); - return Create(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages, isLocked: true); + return Create(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages); } public PersistentSession CompleteMessages(OrchestrationRuntimeState newState, IList addedScheduledMessages) @@ -74,31 +74,31 @@ public PersistentSession CompleteMessages(OrchestrationRuntimeState newState, IL { newScheduledMessages = this.ScheduledMessages.AddRange(addedScheduledMessages.Select(tm => ReceivableTaskMessage.Create(tm))); } - return Create(this.SessionId, newSessionState, newMessages, newScheduledMessages, isLocked: false); + return Create(this.SessionId, newSessionState, newMessages, newScheduledMessages); } public PersistentSession AppendMessage(TaskMessage message) { var newMessages = this.Messages.Add(ReceivableTaskMessage.Create(message)); - return Create(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages, this.IsLocked); + return Create(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages); } public PersistentSession AppendMessageBatch(IEnumerable addedMessages) { var newMessages = this.Messages.AddRange(addedMessages.Select(m => ReceivableTaskMessage.Create(m))); - return Create(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages, this.IsLocked); + return Create(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages); } public static PersistentSession CreateWithNewMessage(string sessionId, TaskMessage newMessage) { var newMessages = ImmutableList.Empty.Add(ReceivableTaskMessage.Create(newMessage)); - return Create(sessionId, sessionState: null, messages: newMessages, scheduledMessages: null, isLocked: false); + return Create(sessionId, sessionState: null, messages: newMessages, scheduledMessages: null); } public static PersistentSession CreateWithNewMessages(string sessionId, IEnumerable allMessages) { var newMessages = ImmutableList.Empty.AddRange(allMessages.Select(newMessage => ReceivableTaskMessage.Create(newMessage))); - return Create(sessionId, sessionState: null, messages: newMessages, scheduledMessages: null, isLocked: false); + return Create(sessionId, sessionState: null, messages: newMessages, scheduledMessages: null); } } } diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index 39decb985..ad81c3aed 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -52,8 +52,6 @@ public sealed partial class PersistentSession [DataMember] IEnumerable scheduledMessages { get; set; } - public bool IsLocked { get; } - [OnDeserialized] private void OnDeserialized(StreamingContext context) { @@ -62,18 +60,17 @@ private void OnDeserialized(StreamingContext context) this.scheduledMessages = this.scheduledMessages.ToImmutableList(); } - private PersistentSession(string sessionId, IImmutableList sessionState, IImmutableList messages, IImmutableList scheduledMessages, bool isLocked) + private PersistentSession(string sessionId, IImmutableList sessionState, IImmutableList messages, IImmutableList scheduledMessages) { this.SessionId = sessionId; this.sessionState = sessionState ?? ImmutableList.Empty; this.messages = messages ?? ImmutableList.Empty; this.scheduledMessages = scheduledMessages ?? ImmutableList.Empty; - this.IsLocked = isLocked; } - public static PersistentSession Create(string sessionId, IImmutableList sessionState, IImmutableList messages, IImmutableList scheduledMessages, bool isLocked) + public static PersistentSession Create(string sessionId, IImmutableList sessionState, IImmutableList messages, IImmutableList scheduledMessages) { - return new PersistentSession(sessionId, sessionState, messages, scheduledMessages, isLocked); + return new PersistentSession(sessionId, sessionState, messages, scheduledMessages); } public ImmutableList SessionState => this.sessionState.ToImmutableList(); diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 2aaff85d3..86882cf4d 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -28,9 +28,11 @@ public class SessionsProvider readonly IReliableStateManager stateManager; readonly CancellationTokenSource cancellationTokenSource; - readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId, null, null, null, false); + readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId, null, null, null); IReliableDictionary orchestrations; - ConcurrentQueue inMemorySessions = new ConcurrentQueue(); + + ConcurrentQueue inMemorySessionsQueue = new ConcurrentQueue(); + ConcurrentDictionary lockedSessions = new ConcurrentDictionary(); public SessionsProvider(IReliableStateManager stateManager) { @@ -46,6 +48,28 @@ public SessionsProvider(IReliableStateManager stateManager) public async Task StartAsync() { this.orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); + + using (var txn = this.stateManager.CreateTransaction()) + { + var count = await this.orchestrations.GetCountAsync(txn); + + if (count > 0) + { + var enumerable = await this.orchestrations.CreateEnumerableAsync(txn, EnumerationMode.Unordered); + using (var enumerator = enumerable.GetAsyncEnumerator()) + { + while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) + { + var entry = enumerator.Current; + if (entry.Value.Messages.Any()) + { + this.TryEnqueueSession(entry.Key); + } + } + } + } + } + var nowait = ProcessScheduledMessages(); } @@ -70,15 +94,32 @@ async Task ProcessScheduledMessages() } } + if (this.cancellationTokenSource.IsCancellationRequested) + { + break; + } + foreach (var sessionId in scheduledMessageSessions) { using (var txn = this.stateManager.CreateTransaction()) { - await this.orchestrations.AddOrUpdateAsync(txn, sessionId, NewSessionFactory, (sId, oldValue) => oldValue.FireScheduledMessages()); + await this.orchestrations.AddOrUpdateAsync(txn, + sessionId, + NewSessionFactory, + (sId, oldValue) => oldValue.FireScheduledMessages(), + TimeSpan.FromSeconds(4), + this.cancellationTokenSource.Token); + await txn.CommitAsync(); + this.TryEnqueueSession(sessionId); } } + if (this.cancellationTokenSource.IsCancellationRequested) + { + break; + } + await Task.Delay(TimeSpan.FromMilliseconds(100)); } } @@ -95,19 +136,33 @@ public async Task AcceptSessionAsync(TimeSpan receiveTimeout) { string returnSessionId; - if (this.inMemorySessions.TryDequeue(out returnSessionId)) + if (this.inMemorySessionsQueue.TryDequeue(out returnSessionId)) { - using (var txn = this.stateManager.CreateTransaction()) + try { - //Todo: TryUpdate feels more natural here than AddOrUpdateAsync, however what do we do if it fails? - var result = await this.orchestrations.AddOrUpdateAsync(txn, returnSessionId, NewSessionFactory, (sId, oldValue) => oldValue.ReceiveMessages()); - await txn.CommitAsync(); - return result; + using (var txn = this.stateManager.CreateTransaction()) + { + //Todo: TryUpdate feels more natural here than AddOrUpdateAsync, however what do we do if it fails? + var result = await this.orchestrations.AddOrUpdateAsync(txn, returnSessionId, NewSessionFactory, (sId, oldValue) => oldValue.ReceiveMessages()); + await txn.CommitAsync(); + + if (!this.lockedSessions.TryUpdate(returnSessionId, newValue:LockState.Locked, comparisonValue:LockState.InFetchQueue)) + { + throw new Exception("Internal Server Error : Unexpected to dequeue a session which was already locked before"); + } + + return result; + } + } + catch (TimeoutException) + { + this.inMemorySessionsQueue.Enqueue(returnSessionId); + throw; } } + //Todo : Can use a signal mechanism? await Task.Delay(100, this.cancellationTokenSource.Token); - await PopulateInMemorySessions(); } return null; @@ -118,19 +173,34 @@ public List GetSessionMessages(PersistentSession session) return session.Messages.Where(m => m.IsReceived).Select(m => m.TaskMessage).ToList(); } - public async Task CompleteAndUpdateSession(ITransaction transaction, + /// + /// Callers should pass the transaction and once the transaction is commited successfully, + /// should call . + /// + public Task CompleteAndUpdateSession(ITransaction transaction, string sessionId, OrchestrationRuntimeState newSessionState, IList scheduledMessages) { - await this.orchestrations.AddOrUpdateAsync(transaction, sessionId, NewSessionFactory, + return this.orchestrations.AddOrUpdateAsync(transaction, sessionId, NewSessionFactory, (sId, oldValue) => oldValue.CompleteMessages(newSessionState, scheduledMessages)); } - public async Task AppendMessageAsync(ITransaction transaction, TaskMessage newMessage) + public async Task AppendMessageAsync(TaskMessage newMessage) { await EnsureOrchestrationStoreInitialized(); + using (var txn = this.stateManager.CreateTransaction()) + { + await this.AppendMessageAsync(txn, newMessage); + await txn.CommitAsync(); + } + + this.TryEnqueueSession(newMessage.OrchestrationInstance.InstanceId); + } + + public async Task AppendMessageAsync(ITransaction transaction, TaskMessage newMessage) + { Func newSessionFactory = (sId) => PersistentSession.CreateWithNewMessage(sId, newMessage); await this.orchestrations.AddOrUpdateAsync(transaction, newMessage.OrchestrationInstance.InstanceId, @@ -154,9 +224,18 @@ await this.orchestrations.AddOrUpdateAsync(transaction, group.Key, } } - public async Task DropSession(ITransaction transaction, string sessionId) + public void TryUnlockSession(string sessionId, bool putBackInQueue) { - await this.orchestrations.TryRemoveAsync(transaction, sessionId); + LockState lockState; + if (!this.lockedSessions.TryRemove(sessionId, out lockState) || lockState != LockState.Locked) + { + throw new Exception("Internal Server Error : Unexpectedly trying to unlock a session which was not locked."); + } + + if (putBackInQueue) + { + TryEnqueueSession(sessionId); + } } public async Task SessionExists(string sessionId) @@ -178,26 +257,24 @@ async Task EnsureOrchestrationStoreInitialized() } } - async Task PopulateInMemorySessions() + public void TryEnqueueSession(string sessionId) { - if (!this.cancellationTokenSource.IsCancellationRequested) + if (this.lockedSessions.TryAdd(sessionId, LockState.InFetchQueue)) { - using (var txn = this.stateManager.CreateTransaction()) - { - var enumerable = await this.orchestrations.CreateEnumerableAsync(txn, EnumerationMode.Unordered); - using (var enumerator = enumerable.GetAsyncEnumerator()) - { - while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) - { - var entry = enumerator.Current; - if (!entry.Value.IsLocked && entry.Value.Messages.Any()) - { - this.inMemorySessions.Enqueue(entry.Key); - } - } - } - } + this.inMemorySessionsQueue.Enqueue(sessionId); } } + + public async Task DropSession(ITransaction transaction, string sessionId) + { + await this.orchestrations.TryRemoveAsync(transaction, sessionId); + } + + enum LockState + { + InFetchQueue = 0, + + Locked, + } } } From d14392577b349ab8dae8d00c28b43159a03ae3ba Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 26 Sep 2016 14:37:50 -0700 Subject: [PATCH 095/210] Clearing a todo : Using signalling mechanism for AcceptSession (like it was done for activities). --- .../SessionsProvider.cs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 86882cf4d..034d539ff 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -34,6 +34,8 @@ public class SessionsProvider ConcurrentQueue inMemorySessionsQueue = new ConcurrentQueue(); ConcurrentDictionary lockedSessions = new ConcurrentDictionary(); + readonly AsyncManualResetEvent waitEvent = new AsyncManualResetEvent(); + public SessionsProvider(IReliableStateManager stateManager) { if (stateManager == null) @@ -131,10 +133,12 @@ public void Stop() public async Task AcceptSessionAsync(TimeSpan receiveTimeout) { - Stopwatch timer = Stopwatch.StartNew(); - while (timer.Elapsed < receiveTimeout && !this.cancellationTokenSource.IsCancellationRequested) + ThrowIfStopped(); + + string returnSessionId; + bool newItemsBeforeTimeout = true; + while (newItemsBeforeTimeout) { - string returnSessionId; if (this.inMemorySessionsQueue.TryDequeue(out returnSessionId)) { @@ -161,8 +165,8 @@ public async Task AcceptSessionAsync(TimeSpan receiveTimeout) } } - //Todo : Can use a signal mechanism? - await Task.Delay(100, this.cancellationTokenSource.Token); + this.waitEvent.Reset(); + newItemsBeforeTimeout = await this.waitEvent.WaitAsync(receiveTimeout, this.cancellationTokenSource.Token); } return null; @@ -188,6 +192,7 @@ public Task CompleteAndUpdateSession(ITransaction transaction public async Task AppendMessageAsync(TaskMessage newMessage) { + ThrowIfStopped(); await EnsureOrchestrationStoreInitialized(); using (var txn = this.stateManager.CreateTransaction()) @@ -201,6 +206,7 @@ public async Task AppendMessageAsync(TaskMessage newMessage) public async Task AppendMessageAsync(ITransaction transaction, TaskMessage newMessage) { + ThrowIfStopped(); Func newSessionFactory = (sId) => PersistentSession.CreateWithNewMessage(sId, newMessage); await this.orchestrations.AddOrUpdateAsync(transaction, newMessage.OrchestrationInstance.InstanceId, @@ -210,6 +216,7 @@ await this.orchestrations.AddOrUpdateAsync(transaction, newMessage.Orchestration public async Task AppendMessageBatchAsync(ITransaction transaction, IEnumerable newMessages) { + ThrowIfStopped(); var groups = newMessages.GroupBy(m => m.OrchestrationInstance.InstanceId); foreach (var group in groups) @@ -262,6 +269,7 @@ public void TryEnqueueSession(string sessionId) if (this.lockedSessions.TryAdd(sessionId, LockState.InFetchQueue)) { this.inMemorySessionsQueue.Enqueue(sessionId); + this.waitEvent.Set(); } } @@ -270,6 +278,11 @@ public async Task DropSession(ITransaction transaction, string sessionId) await this.orchestrations.TryRemoveAsync(transaction, sessionId); } + void ThrowIfStopped() + { + this.cancellationTokenSource.Token.ThrowIfCancellationRequested(); + } + enum LockState { InFetchQueue = 0, From 9e2bc08a8014090caa4524628db6718768ad640f Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 4 Oct 2016 11:43:05 -0700 Subject: [PATCH 096/210] Changes for trying out timeout wrapper in orchestrations. Note that timer needs to be explicitly cancelled once the main task finished because otherwise the orchestration will wait for timer to complete firing taking it more time than needed. This is by design in Durable task framework. (It would be same for main task in the sense that if timer fires first, somehow main task needs to be cancelled, for the test implementation I considered that optional and left it out) --- .../FunctionalTests.cs | 39 +++++++++++++++++++ .../Perf/TestOrchestration.cs | 32 +++++++++++++++ .../Perf/TestOrchestrationData.cs | 6 +++ 3 files changed, 77 insertions(+) diff --git a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs index 36f266219..81d9aec35 100644 --- a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs @@ -13,6 +13,7 @@ using System; using System.Threading.Tasks; +using DurableTask.Test.Orchestrations.Perf; using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -76,6 +77,44 @@ public async Task Orchestration_With_SubOrchestration_Finishes() Assert.AreEqual($"\"TaskResult = Hello World , SubOrchestration1Result = Hello Gabbar, SubOrchestration2Result = Hello Gabbar\"", result.Output); } + [TestMethod] + public async Task Orchestration_With_TimeoutWrapper_Test() + { + // Task finishes within timeout + var instance = await this.serviceClient.StartTestOrchestrationAsync(new TestOrchestrationData() + { + NumberOfParallelTasks = 0, + NumberOfSerialTasks = 1, + MaxDelay = 0, + MinDelay = 0, + DelayUnit = TimeSpan.FromMilliseconds(1), + UseTimeoutTask = true, + ExecutionTimeout = TimeSpan.FromMinutes(1) + }); + var result = await this.serviceClient.WaitForOrchestration(instance, TimeSpan.FromMinutes(2)); + + Assert.IsNotNull(result); + Assert.AreEqual(OrchestrationStatus.Completed, result.OrchestrationStatus); + Console.WriteLine($"Time for Orchestration with no delay running task wrapped in 1 minute timeout : {result.CompletedTime - result.CreatedTime}"); + + // Task does not finish within timeout + instance = await this.serviceClient.StartTestOrchestrationAsync(new TestOrchestrationData() + { + NumberOfParallelTasks = 0, + NumberOfSerialTasks = 1, + MaxDelay = 5, + MinDelay = 5, + DelayUnit = TimeSpan.FromSeconds(1), + UseTimeoutTask = true, + ExecutionTimeout = TimeSpan.FromSeconds(1) + }); + result = await this.serviceClient.WaitForOrchestration(instance, TimeSpan.FromMinutes(2)); + + Assert.IsNotNull(result); + Assert.AreEqual(OrchestrationStatus.Failed, result.OrchestrationStatus); + Console.WriteLine($"Time for Orchestration with 5 second running task wrapped in 1 second timeout : {result.CompletedTime - result.CreatedTime}"); + } + [TestMethod] public async Task Purge_Removes_State() { diff --git a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs index 45e279f25..560f62ffa 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs @@ -11,6 +11,8 @@ // limitations under the License. // ---------------------------------------------------------------------------------- +using System.Threading; + namespace DurableTask.Test.Orchestrations.Perf { using System; @@ -22,6 +24,18 @@ namespace DurableTask.Test.Orchestrations.Perf public class TestOrchestration : TaskOrchestration { public override async Task RunTask(OrchestrationContext context, TestOrchestrationData data) + { + if (data.UseTimeoutTask) + { + return await RunTaskWithTimeout(context, data); + } + else + { + return await RunTaskCore(context, data); + } + } + + async Task RunTaskCore(OrchestrationContext context, TestOrchestrationData data) { int result = 0; List> results = new List>(); @@ -55,5 +69,23 @@ public override async Task RunTask(OrchestrationContext context, TestOrches return result; } + + async Task RunTaskWithTimeout(OrchestrationContext context, TestOrchestrationData data) + { + var timerCts = new CancellationTokenSource(); + + var timer = context.CreateTimer(context.CurrentUtcDateTime.Add(data.ExecutionTimeout), -1, timerCts.Token); + var mainTask = RunTaskCore(context, data); + + var resultTask = await Task.WhenAny(mainTask, timer); + + if (resultTask == timer) + { + throw new TimeoutException("Orchestration timed out"); + } + + timerCts.Cancel(); + return mainTask.Result; + } } } diff --git a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestrationData.cs b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestrationData.cs index dbe80847b..0b4e18ff7 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestrationData.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestrationData.cs @@ -34,5 +34,11 @@ public class TestOrchestrationData [DataMember] public TimeSpan DelayUnit { get; set; } + + [DataMember] + public bool UseTimeoutTask { get; set; } + + [DataMember] + public TimeSpan ExecutionTimeout { get; set; } } } From b4929997ca9c357e8ebb8c1445cf06091ec9baee Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 4 Oct 2016 11:43:05 -0700 Subject: [PATCH 097/210] Changed the stress tests to use timers and take one measurement. Caught a product issue because of that (every iteration of scheduled message check enqueues session for processing even if no scheduled messages are activated) Thie changes fixes the issue as per the current code , however, I am considering rewriting scheduled messages. --- .../StressTests.cs | 24 +++++++++++++++++++ .../SessionsProvider.cs | 22 ++++++++++------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.Test/StressTests.cs b/Test/DurableTask.ServiceFabric.Test/StressTests.cs index ecc61aa32..8e744deb7 100644 --- a/Test/DurableTask.ServiceFabric.Test/StressTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/StressTests.cs @@ -42,6 +42,12 @@ public async Task ExecuteStressTest() } }; + await RunDriverOrchestrationHelper(driverConfig); + Console.WriteLine(); + + driverConfig.SubOrchestrationData.UseTimeoutTask = true; + driverConfig.SubOrchestrationData.ExecutionTimeout = TimeSpan.FromMinutes(2); + await RunDriverOrchestrationHelper(driverConfig); } @@ -57,6 +63,12 @@ public async Task SimplePerformanceExperiment() DelayUnit = TimeSpan.FromSeconds(1) }; + await RunTestOrchestrationsHelper(100, testOrchestratorInput); + Console.WriteLine(); + + testOrchestratorInput.UseTimeoutTask = true; + testOrchestratorInput.ExecutionTimeout = TimeSpan.FromMinutes(2); + await RunTestOrchestrationsHelper(100, testOrchestratorInput); } @@ -72,6 +84,12 @@ public async Task RunThousandOrchsWithHundredMilliSecondDelayInBetweenStartingEa DelayUnit = TimeSpan.FromMilliseconds(1) }; + await RunTestOrchestrationsHelper(1000, testOrchestratorInput, delayGeneratorFunction: (totalRequestsSoFar) => TimeSpan.FromMilliseconds(100)); + Console.WriteLine(); + + testOrchestratorInput.UseTimeoutTask = true; + testOrchestratorInput.ExecutionTimeout = TimeSpan.FromMinutes(2); + await RunTestOrchestrationsHelper(1000, testOrchestratorInput, delayGeneratorFunction: (totalRequestsSoFar) => TimeSpan.FromMilliseconds(100)); } @@ -86,6 +104,12 @@ public async Task InfrequentLoadScenario() MinDelay = 0, }; + await RunTestOrchestrationsHelper(200, testOrchestratorInput, delayGeneratorFunction: (totalRequestsSoFar) => TimeSpan.FromSeconds(1)); + Console.WriteLine(); + + testOrchestratorInput.UseTimeoutTask = true; + testOrchestratorInput.ExecutionTimeout = TimeSpan.FromMinutes(2); + await RunTestOrchestrationsHelper(200, testOrchestratorInput, delayGeneratorFunction: (totalRequestsSoFar) => TimeSpan.FromSeconds(1)); } diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 034d539ff..30dd20ec3 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -105,15 +105,19 @@ async Task ProcessScheduledMessages() { using (var txn = this.stateManager.CreateTransaction()) { - await this.orchestrations.AddOrUpdateAsync(txn, - sessionId, - NewSessionFactory, - (sId, oldValue) => oldValue.FireScheduledMessages(), - TimeSpan.FromSeconds(4), - this.cancellationTokenSource.Token); - - await txn.CommitAsync(); - this.TryEnqueueSession(sessionId); + var existingValue = await this.orchestrations.TryGetValueAsync(txn, sessionId); + if (existingValue.HasValue) + { + var old = existingValue.Value; + var newValue = old.FireScheduledMessages(); + + if (old != newValue) + { + await this.orchestrations.TryUpdateAsync(txn, sessionId, newValue, old, TimeSpan.FromSeconds(4), this.cancellationTokenSource.Token); + await txn.CommitAsync(); + this.TryEnqueueSession(sessionId); + } + } } } From 337cb1043ca1c9c11cdb2a75d59bcdbff2b22b44 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 4 Oct 2016 11:43:05 -0700 Subject: [PATCH 098/210] Using ImmutableSortedSet to improve the time complexity of scheduled message activation (still within the session) and also optimize selecting the scheduled message sessions to process. Doesn't drastically improve perf though it got better a bit, need to experiment with a separate store for all scheduled messages instead of using Orchestrations dictionary. --- .../PersistentSessionTests.cs | 6 +-- .../DurableTask.ServiceFabric.csproj | 1 + .../PersistentSession.api.cs | 40 +++++++++++---- .../PersistentSession.cs | 12 ++--- .../SessionsProvider.cs | 6 ++- .../TimerFiredEventComparer.cs | 51 +++++++++++++++++++ 6 files changed, 95 insertions(+), 21 deletions(-) create mode 100644 src/DurableTask.ServiceFabric/TimerFiredEventComparer.cs diff --git a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs index a1c94f645..87f303559 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs @@ -46,14 +46,14 @@ public void SerializationTest() messages.Add(ReceivableTaskMessage.Create(new TaskMessage() { SequenceNumber = i })); } - var scheduledMessages = new List(); + var scheduledMessages = new List(); for (int i = 0; i < numberOfItemsInCollections; i++) { - scheduledMessages.Add(ReceivableTaskMessage.Create(new TaskMessage() { SequenceNumber = i })); + scheduledMessages.Add(new TaskMessage() { SequenceNumber = i, Event = new TimerFiredEvent(i) {FireAt = DateTime.Now} }); } PersistentSession testSession = PersistentSession.Create("testSession", events.ToImmutableList(), - messages.ToImmutableList(), scheduledMessages.ToImmutableList()); + messages.ToImmutableList(), scheduledMessages.ToImmutableSortedSet(TimerFiredEventComparer.Instance)); using (var stream = new MemoryStream()) { diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 79783d216..20138d3bf 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -90,6 +90,7 @@ + diff --git a/src/DurableTask.ServiceFabric/PersistentSession.api.cs b/src/DurableTask.ServiceFabric/PersistentSession.api.cs index 4dd30a126..1641710b5 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.api.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.api.cs @@ -21,18 +21,18 @@ namespace DurableTask.ServiceFabric public sealed partial class PersistentSession { - // Todo: Can optimize in a few other ways, for now, something that works public PersistentSession FireScheduledMessages() { var messagesBuilder = this.Messages.ToBuilder(); - var remainingScheduledMessagesBuilder = ImmutableList.Empty.ToBuilder(); + var scheduledMessagesBuilder = this.ScheduledMessages.ToBuilder(); bool changed = false; var currentTime = DateTime.UtcNow; - foreach (var scheduledMessage in this.ScheduledMessages) + while (scheduledMessagesBuilder.Count > 0) { - var timerEvent = scheduledMessage.TaskMessage.Event as TimerFiredEvent; + var firstPendingMessage = scheduledMessagesBuilder.Min; + var timerEvent = firstPendingMessage.Event as TimerFiredEvent; if (timerEvent == null) { @@ -42,23 +42,40 @@ public PersistentSession FireScheduledMessages() if (timerEvent.FireAt <= currentTime) { - messagesBuilder.Add(scheduledMessage); + messagesBuilder.Add(ReceivableTaskMessage.Create(firstPendingMessage)); + scheduledMessagesBuilder.Remove(firstPendingMessage); changed = true; } else { - remainingScheduledMessagesBuilder.Add(scheduledMessage); + break; } } if (changed) { - return Create(this.SessionId, this.SessionState, messagesBuilder.ToImmutableList(), remainingScheduledMessagesBuilder.ToImmutableList()); + return Create(this.SessionId, this.SessionState, messagesBuilder.ToImmutableList(), scheduledMessagesBuilder.ToImmutableSortedSet()); } return this; } + public bool HasScheduledMessagesDue(DateTime threshHoldTime) + { + if (this.ScheduledMessages.Count > 0) + { + var firstPendingMessage = this.ScheduledMessages.Min; + var timerEvent = firstPendingMessage.Event as TimerFiredEvent; + + if (timerEvent != null && timerEvent.FireAt <= threshHoldTime) + { + return true; + } + } + + return false; + } + public PersistentSession ReceiveMessages() { var newMessages = this.Messages.ToBuilder().ConvertAll(m => ReceivableTaskMessage.Create(m.TaskMessage, isReceived: true)); @@ -69,12 +86,15 @@ public PersistentSession CompleteMessages(OrchestrationRuntimeState newState, IL { var newMessages = this.Messages.RemoveAll(m => m.IsReceived); var newSessionState = newState?.Events.ToImmutableList(); - var newScheduledMessages = this.ScheduledMessages; + var newScheduledMessagesBuilder = this.ScheduledMessages.ToBuilder(); if (addedScheduledMessages?.Count > 0) { - newScheduledMessages = this.ScheduledMessages.AddRange(addedScheduledMessages.Select(tm => ReceivableTaskMessage.Create(tm))); + foreach (var addedScheduledMessage in addedScheduledMessages) + { + newScheduledMessagesBuilder.Add(addedScheduledMessage); + } } - return Create(this.SessionId, newSessionState, newMessages, newScheduledMessages); + return Create(this.SessionId, newSessionState, newMessages, newScheduledMessagesBuilder.ToImmutableSortedSet()); } public PersistentSession AppendMessage(TaskMessage message) diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index ad81c3aed..23f677245 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -50,32 +50,32 @@ public sealed partial class PersistentSession /// Do not use except in the constructor or serialization methods, use property instead. /// [DataMember] - IEnumerable scheduledMessages { get; set; } + IEnumerable scheduledMessages { get; set; } [OnDeserialized] private void OnDeserialized(StreamingContext context) { this.sessionState = this.sessionState.ToImmutableList(); this.messages = this.messages.ToImmutableList(); - this.scheduledMessages = this.scheduledMessages.ToImmutableList(); + this.scheduledMessages = this.scheduledMessages.ToImmutableSortedSet(TimerFiredEventComparer.Instance); } - private PersistentSession(string sessionId, IImmutableList sessionState, IImmutableList messages, IImmutableList scheduledMessages) + private PersistentSession(string sessionId, IImmutableList sessionState, IImmutableList messages, ImmutableSortedSet scheduledMessages) { this.SessionId = sessionId; this.sessionState = sessionState ?? ImmutableList.Empty; this.messages = messages ?? ImmutableList.Empty; - this.scheduledMessages = scheduledMessages ?? ImmutableList.Empty; + this.scheduledMessages = scheduledMessages ?? ImmutableSortedSet.Empty.WithComparer(TimerFiredEventComparer.Instance); } - public static PersistentSession Create(string sessionId, IImmutableList sessionState, IImmutableList messages, IImmutableList scheduledMessages) + public static PersistentSession Create(string sessionId, IImmutableList sessionState, IImmutableList messages, ImmutableSortedSet scheduledMessages) { return new PersistentSession(sessionId, sessionState, messages, scheduledMessages); } public ImmutableList SessionState => this.sessionState.ToImmutableList(); public ImmutableList Messages => this.messages.ToImmutableList(); - public ImmutableList ScheduledMessages => this.scheduledMessages.ToImmutableList(); + public ImmutableSortedSet ScheduledMessages => this.scheduledMessages.ToImmutableSortedSet(TimerFiredEventComparer.Instance); } [DataContract] diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 30dd20ec3..43416aabd 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -75,11 +75,13 @@ public async Task StartAsync() var nowait = ProcessScheduledMessages(); } + // Todo: Can optimize in a few other ways, for now, something that works async Task ProcessScheduledMessages() { while (!this.cancellationTokenSource.IsCancellationRequested) { var scheduledMessageSessions = new List(); + var now = DateTime.UtcNow; using (var txn = this.stateManager.CreateTransaction()) { var enumerable = await this.orchestrations.CreateEnumerableAsync(txn, EnumerationMode.Unordered); @@ -88,7 +90,7 @@ async Task ProcessScheduledMessages() while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) { var entry = enumerator.Current; - if (entry.Value.ScheduledMessages.Count > 0) + if (entry.Value.HasScheduledMessagesDue(now)) { scheduledMessageSessions.Add(entry.Key); } @@ -105,7 +107,7 @@ async Task ProcessScheduledMessages() { using (var txn = this.stateManager.CreateTransaction()) { - var existingValue = await this.orchestrations.TryGetValueAsync(txn, sessionId); + var existingValue = await this.orchestrations.TryGetValueAsync(txn, sessionId, LockMode.Update); if (existingValue.HasValue) { var old = existingValue.Value; diff --git a/src/DurableTask.ServiceFabric/TimerFiredEventComparer.cs b/src/DurableTask.ServiceFabric/TimerFiredEventComparer.cs new file mode 100644 index 000000000..909b81344 --- /dev/null +++ b/src/DurableTask.ServiceFabric/TimerFiredEventComparer.cs @@ -0,0 +1,51 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace DurableTask.ServiceFabric +{ + using System; + using System.Collections.Generic; + using DurableTask.History; + + public sealed class TimerFiredEventComparer : IComparer + { + public static readonly TimerFiredEventComparer Instance = new TimerFiredEventComparer(); + + public int Compare(TaskMessage first, TaskMessage second) + { + if (first == null) + { + throw new ArgumentNullException(nameof(first)); + } + + if (second == null) + { + throw new ArgumentNullException(nameof(second)); + } + + var firstTimer = first.Event as TimerFiredEvent; + var secondTimer = second.Event as TimerFiredEvent; + + if (firstTimer == null) + { + throw new ArgumentException(nameof(first)); + } + if (secondTimer == null) + { + throw new ArgumentException(nameof(second)); + } + + return DateTime.Compare(firstTimer.FireAt, secondTimer.FireAt); + } + } +} From 075f985d2aca7c5b923132d4b4300763f528a7f5 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 4 Oct 2016 11:43:05 -0700 Subject: [PATCH 099/210] Minor change to test program. --- Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs b/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs index c5afe6f1c..1f497b3be 100644 --- a/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs +++ b/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs @@ -31,6 +31,11 @@ class Program static Dictionary outcomeFrequencies = new Dictionary(); static void Main(string[] args) + { + RunTest().Wait(); + } + + static async Task RunTest() { CancellationTokenSource cts1 = new CancellationTokenSource(); CancellationTokenSource cts2 = new CancellationTokenSource(); @@ -43,10 +48,10 @@ static void Main(string[] args) Console.ReadKey(); cts1.Cancel(); - programTask.Wait(); + await programTask; cts2.Cancel(); - statusTask.Wait(); + await statusTask; watch.Stop(); Func elapsedTimeFormatter = timeSpan => $"{timeSpan.Hours:00}:{timeSpan.Minutes:00}:{timeSpan.Seconds:00}.{timeSpan.Milliseconds / 10:00}"; From 9858cb43e377c4823cef176f39005dd48815c150 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 4 Oct 2016 11:43:05 -0700 Subject: [PATCH 100/210] More fixes to test program. --- .../Program.cs | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs b/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs index 1f497b3be..c2e8981fd 100644 --- a/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs +++ b/Test/DurableTask.ServiceFabric.Stress.Tests/Program.cs @@ -104,26 +104,28 @@ static async Task RunOrchestrations(CancellationToken cancellationToken) { NumberOfParallelTasks = 15, NumberOfSerialTasks = 5, + MaxDelay = 500, + MinDelay = 50, + DelayUnit = TimeSpan.FromMilliseconds(1), + UseTimeoutTask = false, //Change to true when testing timers + ExecutionTimeout = TimeSpan.FromMinutes(5) }; totalRequests++; var instance = await serviceClient.StartTestOrchestrationAsync(newOrchData); instances.Add(instance); - var waitTask = serviceClient.WaitForOrchestration(instance, TimeSpan.FromMinutes(2)); + var waitTask = serviceClient.WaitForOrchestration(instance, TimeSpan.FromMinutes(5)); tasks.Add(waitTask); - if (totalRequests%10 == 0) + var delayBetweenRequests = 100; + try { - var delay = totalRequests%100 == 0 ? TimeSpan.FromSeconds(3) : TimeSpan.FromSeconds(1); - try - { - await Task.Delay(delay, cancellationToken); - } - catch (TaskCanceledException) - { - break; - } + await Task.Delay(TimeSpan.FromMilliseconds(delayBetweenRequests), cancellationToken); + } + catch (TaskCanceledException) + { + break; } } @@ -133,5 +135,19 @@ static async Task RunOrchestrations(CancellationToken cancellationToken) Console.WriteLine("Done"); } + + static int GetVariableDelayForTotalRequests(int totalRequests) + { + int delay = 0; + if (totalRequests%10 == 0) + { + delay = 1000; + } + if (totalRequests%100 == 0) + { + delay = 3000; + } + return delay; + } } } From d45f43cd5b61a113a32646b97a475cd865490cf4 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 4 Oct 2016 11:43:05 -0700 Subject: [PATCH 101/210] Refactoring of common code from PeekLockQueue to a base class. Partial refactoring for now, will evolve it further. --- .../DurableTask.ServiceFabric.csproj | 2 + .../FabricOrchestrationService.cs | 2 - src/DurableTask.ServiceFabric/Message.cs | 34 ++++ .../MessageProviderBase.cs | 149 ++++++++++++++++++ .../PeekLockQueue.cs | 132 +--------------- 5 files changed, 192 insertions(+), 127 deletions(-) create mode 100644 src/DurableTask.ServiceFabric/Message.cs create mode 100644 src/DurableTask.ServiceFabric/MessageProviderBase.cs diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 20138d3bf..6bf7fc2eb 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -79,6 +79,7 @@ + @@ -89,6 +90,7 @@ + diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index d12cc6d4c..a03849128 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -15,11 +15,9 @@ namespace DurableTask.ServiceFabric { using System; using System.Collections.Generic; - using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; - using DurableTask.Common; using DurableTask.Tracking; using Microsoft.ServiceFabric.Data; diff --git a/src/DurableTask.ServiceFabric/Message.cs b/src/DurableTask.ServiceFabric/Message.cs new file mode 100644 index 000000000..ade220425 --- /dev/null +++ b/src/DurableTask.ServiceFabric/Message.cs @@ -0,0 +1,34 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace DurableTask.ServiceFabric +{ + using System; + using System.Runtime.Serialization; + + [DataContract] + class Message where TKey : IComparable, IEquatable + { + public Message(TKey key, TValue value) + { + Key = key; + Value = value; + } + + [DataMember] + public TKey Key { get; private set; } + + [DataMember] + public TValue Value { get; private set; } + } +} diff --git a/src/DurableTask.ServiceFabric/MessageProviderBase.cs b/src/DurableTask.ServiceFabric/MessageProviderBase.cs new file mode 100644 index 000000000..d14ee6d9b --- /dev/null +++ b/src/DurableTask.ServiceFabric/MessageProviderBase.cs @@ -0,0 +1,149 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace DurableTask.ServiceFabric +{ + using System; + using System.Collections.Generic; + using System.Threading; + using System.Threading.Tasks; + using Microsoft.ServiceFabric.Data; + using Microsoft.ServiceFabric.Data.Collections; + + abstract class MessageProviderBase where TKey : IComparable, IEquatable + { + readonly IReliableStateManager stateManager; + readonly string storeName; + readonly CancellationTokenSource cancellationTokenSource; + readonly AsyncManualResetEvent waitEvent = new AsyncManualResetEvent(); + + IReliableDictionary store; + + protected MessageProviderBase(IReliableStateManager stateManager, string storeName) + { + this.stateManager = stateManager; + this.storeName = storeName; + this.cancellationTokenSource = new CancellationTokenSource(); + } + + public async Task StartAsync() + { + this.store = await this.stateManager.GetOrAddAsync>(this.storeName); + + using (var tx = this.stateManager.CreateTransaction()) + { + var count = await this.store.GetCountAsync(tx); + + if (count > 0) + { + var enumerable = await this.store.CreateEnumerableAsync(tx, EnumerationMode.Unordered); + using (var enumerator = enumerable.GetAsyncEnumerator()) + { + while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) + { + AddItemInMemory(enumerator.Current.Key, enumerator.Current.Value); + } + } + } + } + } + + public Task StopAsync() + { + this.cancellationTokenSource.Cancel(); + return Task.FromResult(null); + } + + public Task CompleteAsync(ITransaction tx, TKey key) + { + ThrowIfStopped(); + + return this.store.TryRemoveAsync(tx, key); + } + + /// + /// Caller has to pass in a transaction and must call SendComplete with the same item + /// after the transaction commit succeeded. + /// + public Task SendBeginAsync(ITransaction tx, Message item) + { + ThrowIfStopped(); + + return this.store.TryAddAsync(tx, item.Key, item.Value); + } + + public void SendComplete(Message item) + { + ThrowIfStopped(); + + AddItemInMemory(item.Key, item.Value); + this.waitEvent.Set(); + } + + /// + /// Caller has to pass in a transaction and must call SendBatchComplete with the same items + /// after the transaction commit succeeded. + /// + public async Task SendBatchBeginAsync(ITransaction tx, IEnumerable> items) + { + ThrowIfStopped(); + + foreach (var item in items) + { + await this.store.TryAddAsync(tx, item.Key, item.Value); + } + } + + public void SendBatchComplete(IEnumerable> items) + { + ThrowIfStopped(); + + foreach (var item in items) + { + AddItemInMemory(item.Key, item.Value); + } + this.waitEvent.Set(); + } + + protected async Task> GetValueAsync(TKey key) + { + using (var tx = this.stateManager.CreateTransaction()) + { + var result = await this.store.TryGetValueAsync(tx, key); + if (result.HasValue) + { + return new Message(key, result.Value); + } + throw new Exception("Internal server error : Unexpectedly ended up not having an item in dictionary while having the item key in memory"); + } + } + + protected Task WaitForItemsAsync(TimeSpan timeout) + { + this.waitEvent.Reset(); + return this.waitEvent.WaitAsync(timeout, this.cancellationTokenSource.Token); + } + + protected void SetWaiterForNewItems() + { + this.waitEvent.Set(); + } + + protected abstract void AddItemInMemory(TKey key, TValue value); + + protected void ThrowIfStopped() + { + this.cancellationTokenSource.Token.ThrowIfCancellationRequested(); + } + } +} diff --git a/src/DurableTask.ServiceFabric/PeekLockQueue.cs b/src/DurableTask.ServiceFabric/PeekLockQueue.cs index f9457a0a5..6f86654b9 100644 --- a/src/DurableTask.ServiceFabric/PeekLockQueue.cs +++ b/src/DurableTask.ServiceFabric/PeekLockQueue.cs @@ -15,57 +15,20 @@ namespace DurableTask.ServiceFabric { using System; using System.Collections.Concurrent; - using System.Collections.Generic; - using System.Runtime.Serialization; - using System.Threading; using System.Threading.Tasks; using Microsoft.ServiceFabric.Data; - using Microsoft.ServiceFabric.Data.Collections; - class PeekLockQueue where TKey : IComparable, IEquatable + class PeekLockQueue : MessageProviderBase where TKey : IComparable, IEquatable { - readonly IReliableStateManager stateManager; - readonly string storeName; - readonly CancellationTokenSource cancellationTokenSource; - - IReliableDictionary store; readonly ConcurrentQueue inMemoryQueue = new ConcurrentQueue(); - readonly AsyncManualResetEvent waitEvent = new AsyncManualResetEvent(); - - public PeekLockQueue(IReliableStateManager stateManager, string storeName) + public PeekLockQueue(IReliableStateManager stateManager, string storeName) : base(stateManager, storeName) { - this.stateManager = stateManager; - this.storeName = storeName; - this.cancellationTokenSource = new CancellationTokenSource(); - } - - public async Task StartAsync() - { - this.store = await this.stateManager.GetOrAddAsync>(this.storeName); - - using (var tx = this.stateManager.CreateTransaction()) - { - var count = await this.store.GetCountAsync(tx); - - if (count > 0) - { - var enumerable = await this.store.CreateEnumerableAsync(tx, EnumerationMode.Unordered); - using (var enumerator = enumerable.GetAsyncEnumerator()) - { - while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) - { - this.inMemoryQueue.Enqueue(enumerator.Current.Key); - } - } - } - } } - public Task StopAsync() + protected override void AddItemInMemory(TKey key, TValue value) { - this.cancellationTokenSource.Cancel(); - return Task.FromResult(null); + this.inMemoryQueue.Enqueue(key); } public async Task> ReceiveAsync(TimeSpan receiveTimeout) @@ -80,15 +43,7 @@ public async Task> ReceiveAsync(TimeSpan receiveTimeout) { try { - using (var txn = this.stateManager.CreateTransaction()) - { - var result = await this.store.TryGetValueAsync(txn, key); - if (result.HasValue) - { - return new Message(key, result.Value); - } - throw new Exception("Internal server error : Unexpectedly ended up not having an item in dictionary while having the item key in memory"); - } + return await GetValueAsync(key); } catch (TimeoutException) { @@ -97,92 +52,19 @@ public async Task> ReceiveAsync(TimeSpan receiveTimeout) } } - this.waitEvent.Reset(); - newItemsBeforeTimeout = await this.waitEvent.WaitAsync(receiveTimeout, this.cancellationTokenSource.Token); + newItemsBeforeTimeout = await WaitForItemsAsync(receiveTimeout); } return null; } - public Task CompleteAsync(ITransaction tx, TKey key) - { - ThrowIfStopped(); - - return this.store.TryRemoveAsync(tx, key); - } - - /// - /// Caller has to pass in a transaction and must call SendComplete with the same item - /// after the transaction commit succeeded. - /// - public Task SendBeginAsync(ITransaction tx, Message item) - { - ThrowIfStopped(); - - return this.store.TryAddAsync(tx, item.Key, item.Value); - } - - public void SendComplete(Message item) - { - ThrowIfStopped(); - - this.inMemoryQueue.Enqueue(item.Key); - this.waitEvent.Set(); - } - - /// - /// Caller has to pass in a transaction and must call SendBatchComplete with the same items - /// after the transaction commit succeeded. - /// - public async Task SendBatchBeginAsync(ITransaction tx, IEnumerable> items) - { - ThrowIfStopped(); - - foreach (var item in items) - { - await this.store.TryAddAsync(tx, item.Key, item.Value); - } - } - - public void SendBatchComplete(IEnumerable> items) - { - ThrowIfStopped(); - - foreach (var item in items) - { - this.inMemoryQueue.Enqueue(item.Key); - } - this.waitEvent.Set(); - } - public Task AandonAsync(TKey key) { ThrowIfStopped(); this.inMemoryQueue.Enqueue(key); - this.waitEvent.Set(); + SetWaiterForNewItems(); return Task.FromResult(null); } - - void ThrowIfStopped() - { - this.cancellationTokenSource.Token.ThrowIfCancellationRequested(); - } - } - - [DataContract] - class Message where TKey : IComparable, IEquatable - { - public Message(TKey key, TValue value) - { - Key = key; - Value = value; - } - - [DataMember] - public TKey Key { get; private set; } - - [DataMember] - public TValue Value { get; private set; } } } From d230b7f3680cfcff2a6580e984fbca1a19fc388c Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 4 Oct 2016 11:43:05 -0700 Subject: [PATCH 102/210] Renaming file/class. --- .../{PeekLockQueue.cs => ActivityProvider.cs} | 4 ++-- .../DurableTask.ServiceFabric.csproj | 2 +- src/DurableTask.ServiceFabric/FabricOrchestrationService.cs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename src/DurableTask.ServiceFabric/{PeekLockQueue.cs => ActivityProvider.cs} (90%) diff --git a/src/DurableTask.ServiceFabric/PeekLockQueue.cs b/src/DurableTask.ServiceFabric/ActivityProvider.cs similarity index 90% rename from src/DurableTask.ServiceFabric/PeekLockQueue.cs rename to src/DurableTask.ServiceFabric/ActivityProvider.cs index 6f86654b9..0ea5fdc57 100644 --- a/src/DurableTask.ServiceFabric/PeekLockQueue.cs +++ b/src/DurableTask.ServiceFabric/ActivityProvider.cs @@ -18,11 +18,11 @@ namespace DurableTask.ServiceFabric using System.Threading.Tasks; using Microsoft.ServiceFabric.Data; - class PeekLockQueue : MessageProviderBase where TKey : IComparable, IEquatable + class ActivityProvider : MessageProviderBase where TKey : IComparable, IEquatable { readonly ConcurrentQueue inMemoryQueue = new ConcurrentQueue(); - public PeekLockQueue(IReliableStateManager stateManager, string storeName) : base(stateManager, storeName) + public ActivityProvider(IReliableStateManager stateManager, string storeName) : base(stateManager, storeName) { } diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 6bf7fc2eb..a213b741b 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -81,7 +81,7 @@ - + PersistentSession.cs diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index a03849128..5a73ac0b6 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -27,7 +27,7 @@ public class FabricOrchestrationService : IOrchestrationService IFabricOrchestrationServiceInstanceStore instanceStore; SessionsProvider orchestrationProvider; - PeekLockQueue activitiesProvider; + ActivityProvider activitiesProvider; public FabricOrchestrationService(IReliableStateManager stateManager, SessionsProvider orchestrationProvider, IFabricOrchestrationServiceInstanceStore instanceStore) { @@ -43,7 +43,7 @@ public FabricOrchestrationService(IReliableStateManager stateManager, SessionsPr public async Task StartAsync() { - this.activitiesProvider = new PeekLockQueue(this.stateManager, Constants.ActivitiesQueueName); + this.activitiesProvider = new ActivityProvider(this.stateManager, Constants.ActivitiesQueueName); await this.activitiesProvider.StartAsync(); await this.instanceStore.StartAsync(); await this.orchestrationProvider.StartAsync(); From 519b7118e77cc7f9691f4c1c6966924700300a05 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 4 Oct 2016 11:43:05 -0700 Subject: [PATCH 103/210] Minor bug fixes. --- src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs | 5 +++++ src/DurableTask.ServiceFabric/Message.cs | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs b/src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs index aa76d25a6..c23fc3b33 100644 --- a/src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs +++ b/src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs @@ -28,6 +28,11 @@ public AsyncManualResetEvent() public async Task WaitAsync(TimeSpan timeout, CancellationToken cancellationToken) { + if (timeout < TimeSpan.Zero) + { + timeout = TimeSpan.Zero; + } + var delayTask = Task.Delay(timeout, cancellationToken); var resultTask = await Task.WhenAny(delayTask, this.tcs.Task); return delayTask != resultTask; diff --git a/src/DurableTask.ServiceFabric/Message.cs b/src/DurableTask.ServiceFabric/Message.cs index ade220425..747a403f0 100644 --- a/src/DurableTask.ServiceFabric/Message.cs +++ b/src/DurableTask.ServiceFabric/Message.cs @@ -21,6 +21,16 @@ class Message where TKey : IComparable, IEquatable { public Message(TKey key, TValue value) { + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + Key = key; Value = value; } From a3f30f56bf7acf4ac700b4b6828fec90907060be Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 4 Oct 2016 11:43:05 -0700 Subject: [PATCH 104/210] An alternative implementation for scheduled messages (i.e., timers). There are a couple of todo's in the code, and also I need to measure the CPU difference. --- .../PersistentSessionTests.cs | 9 +- src/DurableTask.ServiceFabric/Constants.cs | 1 + .../DurableTask.ServiceFabric.csproj | 1 + .../FabricOrchestrationService.cs | 76 ++++++--- .../MessageProviderBase.cs | 51 ++++-- .../PersistentSession.api.cs | 77 +-------- .../PersistentSession.cs | 15 +- .../ScheduledMessageProvider.cs | 146 ++++++++++++++++++ .../SessionsProvider.cs | 112 ++++++-------- .../TimerFiredEventComparer.cs | 18 +-- 10 files changed, 306 insertions(+), 200 deletions(-) create mode 100644 src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs diff --git a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs index 87f303559..43770ac38 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs @@ -46,14 +46,8 @@ public void SerializationTest() messages.Add(ReceivableTaskMessage.Create(new TaskMessage() { SequenceNumber = i })); } - var scheduledMessages = new List(); - for (int i = 0; i < numberOfItemsInCollections; i++) - { - scheduledMessages.Add(new TaskMessage() { SequenceNumber = i, Event = new TimerFiredEvent(i) {FireAt = DateTime.Now} }); - } - PersistentSession testSession = PersistentSession.Create("testSession", events.ToImmutableList(), - messages.ToImmutableList(), scheduledMessages.ToImmutableSortedSet(TimerFiredEventComparer.Instance)); + messages.ToImmutableList()); using (var stream = new MemoryStream()) { @@ -73,7 +67,6 @@ public void SerializationTest() Assert.AreEqual("testSession", deserialized.SessionId); Assert.AreEqual(numberOfItemsInCollections*2 + 2, deserialized.SessionState.Count); Assert.AreEqual(numberOfItemsInCollections, deserialized.Messages.Count); - Assert.AreEqual(numberOfItemsInCollections, deserialized.ScheduledMessages.Count); } } } diff --git a/src/DurableTask.ServiceFabric/Constants.cs b/src/DurableTask.ServiceFabric/Constants.cs index 3ea8a1c7d..37283c550 100644 --- a/src/DurableTask.ServiceFabric/Constants.cs +++ b/src/DurableTask.ServiceFabric/Constants.cs @@ -18,5 +18,6 @@ static class Constants internal const string OrchestrationDictionaryName = "Orchestrations"; internal const string ActivitiesQueueName = "Activities"; internal const string InstanceStoreDictionaryName = "InstanceStore"; + internal const string ScheduledMessagesDictionaryName = "ScheduledMessages"; } } diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index a213b741b..cbb440c22 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -91,6 +91,7 @@ + diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 5a73ac0b6..d168355f1 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -23,11 +23,11 @@ namespace DurableTask.ServiceFabric public class FabricOrchestrationService : IOrchestrationService { - IReliableStateManager stateManager; - IFabricOrchestrationServiceInstanceStore instanceStore; - - SessionsProvider orchestrationProvider; - ActivityProvider activitiesProvider; + readonly IReliableStateManager stateManager; + readonly IFabricOrchestrationServiceInstanceStore instanceStore; + readonly SessionsProvider orchestrationProvider; + readonly ActivityProvider activitiesProvider; + readonly ScheduledMessageProvider scheduledMessagesProvider; public FabricOrchestrationService(IReliableStateManager stateManager, SessionsProvider orchestrationProvider, IFabricOrchestrationServiceInstanceStore instanceStore) { @@ -39,12 +39,14 @@ public FabricOrchestrationService(IReliableStateManager stateManager, SessionsPr this.stateManager = stateManager; this.orchestrationProvider = orchestrationProvider; this.instanceStore = instanceStore; + this.activitiesProvider = new ActivityProvider(this.stateManager, Constants.ActivitiesQueueName); + this.scheduledMessagesProvider = new ScheduledMessageProvider(this.stateManager, Constants.ScheduledMessagesDictionaryName, orchestrationProvider); } public async Task StartAsync() { - this.activitiesProvider = new ActivityProvider(this.stateManager, Constants.ActivitiesQueueName); await this.activitiesProvider.StartAsync(); + await this.scheduledMessagesProvider.StartAsync(); await this.instanceStore.StartAsync(); await this.orchestrationProvider.StartAsync(); } @@ -56,8 +58,9 @@ public Task StopAsync() public async Task StopAsync(bool isForced) { - this.orchestrationProvider.Stop(); + await this.orchestrationProvider.StopAsync(); await this.instanceStore.StopAsync(isForced); + await this.scheduledMessagesProvider.StopAsync(); await this.activitiesProvider.StopAsync(); } @@ -85,7 +88,13 @@ public Task DeleteAsync() public async Task DeleteAsync(bool deleteInstanceStore) { await this.stateManager.RemoveAsync(Constants.OrchestrationDictionaryName); + await this.stateManager.RemoveAsync(Constants.ScheduledMessagesDictionaryName); await this.stateManager.RemoveAsync(Constants.ActivitiesQueueName); + + if (deleteInstanceStore) + { + await this.stateManager.RemoveAsync(Constants.InstanceStoreDictionaryName); + } } public bool IsMaxMessageCountExceeded(int currentMessageCount, OrchestrationRuntimeState runtimeState) @@ -160,14 +169,36 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( using (var txn = this.stateManager.CreateTransaction()) { - var activityMessages = outboundMessages.Select(m => new Message(Guid.NewGuid().ToString(), m)).ToList(); - await this.activitiesProvider.SendBatchBeginAsync(txn, activityMessages); + var previousState = workItem.OrchestrationRuntimeState; + IList sessionsToEnqueue = null; + List> scheduledMessages = null; + List> activityMessages = null; - var newSessionValue = await this.orchestrationProvider.CompleteAndUpdateSession(txn, workItem.InstanceId, newOrchestrationRuntimeState, timerMessages); + var newSessionValue = await this.orchestrationProvider.CompleteAndUpdateSession(txn, workItem.InstanceId, newOrchestrationRuntimeState); + + if (outboundMessages?.Count > 0) + { + activityMessages = outboundMessages.Select(m => new Message(Guid.NewGuid().ToString(), m)).ToList(); + await this.activitiesProvider.SendBatchBeginAsync(txn, activityMessages); + } + + if (timerMessages?.Count > 0) + { + scheduledMessages = timerMessages.Select(m => new Message(Guid.NewGuid().ToString(), m)).ToList(); + await this.scheduledMessagesProvider.SendBatchBeginAsync(txn, scheduledMessages); + } if (orchestratorMessages?.Count > 0) { - await this.orchestrationProvider.AppendMessageBatchAsync(txn, orchestratorMessages); + if (previousState?.ParentInstance != null) + { + sessionsToEnqueue = await this.orchestrationProvider.TryAppendMessageBatchAsync(txn, orchestratorMessages); + } + else + { + await this.orchestrationProvider.AppendMessageBatchAsync(txn, orchestratorMessages); + sessionsToEnqueue = orchestratorMessages.Select(m => m.OrchestrationInstance.InstanceId).ToList(); + } } if (this.instanceStore != null) @@ -183,13 +214,20 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( await txn.CommitAsync(); - this.activitiesProvider.SendBatchComplete(activityMessages); this.orchestrationProvider.TryUnlockSession(workItem.InstanceId, putBackInQueue: newSessionValue.Messages.Any()); - if (orchestratorMessages != null) + if (activityMessages != null) { - foreach (var subOrchMessage in orchestratorMessages) + this.activitiesProvider.SendBatchComplete(activityMessages); + } + if (scheduledMessages != null) + { + this.scheduledMessagesProvider.SendBatchComplete(scheduledMessages); + } + if (sessionsToEnqueue != null) + { + foreach (var sessionId in sessionsToEnqueue) { - this.orchestrationProvider.TryEnqueueSession(subOrchMessage.OrchestrationInstance.InstanceId); + this.orchestrationProvider.TryEnqueueSession(sessionId); } } } @@ -239,13 +277,15 @@ public async Task LockNextTaskActivityWorkItem(TimeSpan re public async Task CompleteTaskActivityWorkItemAsync(TaskActivityWorkItem workItem, TaskMessage responseMessage) { - //Todo : If we check for cancellation token, then we could avoid harmless FabricNotPrimaryExceptions that happen when primary node switches using (var txn = this.stateManager.CreateTransaction()) { await this.activitiesProvider.CompleteAsync(txn, workItem.Id); - await this.orchestrationProvider.AppendMessageAsync(txn, responseMessage); + bool added = await this.orchestrationProvider.TryAppendMessageAsync(txn, responseMessage); await txn.CommitAsync(); - this.orchestrationProvider.TryEnqueueSession(responseMessage.OrchestrationInstance.InstanceId); + if (added) + { + this.orchestrationProvider.TryEnqueueSession(responseMessage.OrchestrationInstance.InstanceId); + } } } diff --git a/src/DurableTask.ServiceFabric/MessageProviderBase.cs b/src/DurableTask.ServiceFabric/MessageProviderBase.cs index d14ee6d9b..54ffd147e 100644 --- a/src/DurableTask.ServiceFabric/MessageProviderBase.cs +++ b/src/DurableTask.ServiceFabric/MessageProviderBase.cs @@ -22,31 +22,34 @@ namespace DurableTask.ServiceFabric abstract class MessageProviderBase where TKey : IComparable, IEquatable { - readonly IReliableStateManager stateManager; readonly string storeName; readonly CancellationTokenSource cancellationTokenSource; readonly AsyncManualResetEvent waitEvent = new AsyncManualResetEvent(); - IReliableDictionary store; - protected MessageProviderBase(IReliableStateManager stateManager, string storeName) { - this.stateManager = stateManager; + this.StateManager = stateManager; this.storeName = storeName; this.cancellationTokenSource = new CancellationTokenSource(); } - public async Task StartAsync() + protected IReliableStateManager StateManager { get; } + + protected CancellationToken CancellationToken => this.cancellationTokenSource.Token; + + protected IReliableDictionary Store { get; private set; } + + public virtual async Task StartAsync() { - this.store = await this.stateManager.GetOrAddAsync>(this.storeName); + await InitializeStore(); - using (var tx = this.stateManager.CreateTransaction()) + using (var tx = this.StateManager.CreateTransaction()) { - var count = await this.store.GetCountAsync(tx); + var count = await this.Store.GetCountAsync(tx); if (count > 0) { - var enumerable = await this.store.CreateEnumerableAsync(tx, EnumerationMode.Unordered); + var enumerable = await this.Store.CreateEnumerableAsync(tx, EnumerationMode.Unordered); using (var enumerator = enumerable.GetAsyncEnumerator()) { while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) @@ -58,6 +61,11 @@ public async Task StartAsync() } } + protected async Task InitializeStore() + { + this.Store = await this.StateManager.GetOrAddAsync>(this.storeName); + } + public Task StopAsync() { this.cancellationTokenSource.Cancel(); @@ -68,7 +76,17 @@ public Task CompleteAsync(ITransaction tx, TKey key) { ThrowIfStopped(); - return this.store.TryRemoveAsync(tx, key); + return this.Store.TryRemoveAsync(tx, key); + } + + public async Task CompleteBatchAsync(ITransaction tx, IEnumerable keys) + { + ThrowIfStopped(); + + foreach (var key in keys) + { + await this.Store.TryRemoveAsync(tx, key); + } } /// @@ -79,7 +97,7 @@ public Task SendBeginAsync(ITransaction tx, Message item) { ThrowIfStopped(); - return this.store.TryAddAsync(tx, item.Key, item.Value); + return this.Store.TryAddAsync(tx, item.Key, item.Value); } public void SendComplete(Message item) @@ -100,7 +118,7 @@ public async Task SendBatchBeginAsync(ITransaction tx, IEnumerable> items) protected async Task> GetValueAsync(TKey key) { - using (var tx = this.stateManager.CreateTransaction()) + using (var tx = this.StateManager.CreateTransaction()) { - var result = await this.store.TryGetValueAsync(tx, key); + var result = await this.Store.TryGetValueAsync(tx, key); if (result.HasValue) { return new Message(key, result.Value); @@ -145,5 +163,10 @@ protected void ThrowIfStopped() { this.cancellationTokenSource.Token.ThrowIfCancellationRequested(); } + + protected bool IsStopped() + { + return this.cancellationTokenSource.IsCancellationRequested; + } } } diff --git a/src/DurableTask.ServiceFabric/PersistentSession.api.cs b/src/DurableTask.ServiceFabric/PersistentSession.api.cs index 1641710b5..5c970f119 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.api.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.api.cs @@ -21,104 +21,41 @@ namespace DurableTask.ServiceFabric public sealed partial class PersistentSession { - public PersistentSession FireScheduledMessages() - { - var messagesBuilder = this.Messages.ToBuilder(); - var scheduledMessagesBuilder = this.ScheduledMessages.ToBuilder(); - - bool changed = false; - var currentTime = DateTime.UtcNow; - - while (scheduledMessagesBuilder.Count > 0) - { - var firstPendingMessage = scheduledMessagesBuilder.Min; - var timerEvent = firstPendingMessage.Event as TimerFiredEvent; - - if (timerEvent == null) - { - //Should not happen with the current assumptions - throw new Exception("Internal server error."); - } - - if (timerEvent.FireAt <= currentTime) - { - messagesBuilder.Add(ReceivableTaskMessage.Create(firstPendingMessage)); - scheduledMessagesBuilder.Remove(firstPendingMessage); - changed = true; - } - else - { - break; - } - } - - if (changed) - { - return Create(this.SessionId, this.SessionState, messagesBuilder.ToImmutableList(), scheduledMessagesBuilder.ToImmutableSortedSet()); - } - - return this; - } - - public bool HasScheduledMessagesDue(DateTime threshHoldTime) - { - if (this.ScheduledMessages.Count > 0) - { - var firstPendingMessage = this.ScheduledMessages.Min; - var timerEvent = firstPendingMessage.Event as TimerFiredEvent; - - if (timerEvent != null && timerEvent.FireAt <= threshHoldTime) - { - return true; - } - } - - return false; - } - public PersistentSession ReceiveMessages() { var newMessages = this.Messages.ToBuilder().ConvertAll(m => ReceivableTaskMessage.Create(m.TaskMessage, isReceived: true)); - return Create(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages); + return Create(this.SessionId, this.SessionState, newMessages); } - public PersistentSession CompleteMessages(OrchestrationRuntimeState newState, IList addedScheduledMessages) + public PersistentSession CompleteMessages(OrchestrationRuntimeState newState) { var newMessages = this.Messages.RemoveAll(m => m.IsReceived); var newSessionState = newState?.Events.ToImmutableList(); - var newScheduledMessagesBuilder = this.ScheduledMessages.ToBuilder(); - if (addedScheduledMessages?.Count > 0) - { - foreach (var addedScheduledMessage in addedScheduledMessages) - { - newScheduledMessagesBuilder.Add(addedScheduledMessage); - } - } - return Create(this.SessionId, newSessionState, newMessages, newScheduledMessagesBuilder.ToImmutableSortedSet()); + return Create(this.SessionId, newSessionState, newMessages); } public PersistentSession AppendMessage(TaskMessage message) { var newMessages = this.Messages.Add(ReceivableTaskMessage.Create(message)); - return Create(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages); + return Create(this.SessionId, this.SessionState, newMessages); } public PersistentSession AppendMessageBatch(IEnumerable addedMessages) { var newMessages = this.Messages.AddRange(addedMessages.Select(m => ReceivableTaskMessage.Create(m))); - return Create(this.SessionId, this.SessionState, newMessages, this.ScheduledMessages); + return Create(this.SessionId, this.SessionState, newMessages); } public static PersistentSession CreateWithNewMessage(string sessionId, TaskMessage newMessage) { var newMessages = ImmutableList.Empty.Add(ReceivableTaskMessage.Create(newMessage)); - return Create(sessionId, sessionState: null, messages: newMessages, scheduledMessages: null); + return Create(sessionId, sessionState: null, messages: newMessages); } public static PersistentSession CreateWithNewMessages(string sessionId, IEnumerable allMessages) { var newMessages = ImmutableList.Empty.AddRange(allMessages.Select(newMessage => ReceivableTaskMessage.Create(newMessage))); - return Create(sessionId, sessionState: null, messages: newMessages, scheduledMessages: null); + return Create(sessionId, sessionState: null, messages: newMessages); } } } diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index 23f677245..e355780c8 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -46,36 +46,27 @@ public sealed partial class PersistentSession [DataMember] IEnumerable messages { get; set; } - /// - /// Do not use except in the constructor or serialization methods, use property instead. - /// - [DataMember] - IEnumerable scheduledMessages { get; set; } - [OnDeserialized] private void OnDeserialized(StreamingContext context) { this.sessionState = this.sessionState.ToImmutableList(); this.messages = this.messages.ToImmutableList(); - this.scheduledMessages = this.scheduledMessages.ToImmutableSortedSet(TimerFiredEventComparer.Instance); } - private PersistentSession(string sessionId, IImmutableList sessionState, IImmutableList messages, ImmutableSortedSet scheduledMessages) + private PersistentSession(string sessionId, IImmutableList sessionState, IImmutableList messages) { this.SessionId = sessionId; this.sessionState = sessionState ?? ImmutableList.Empty; this.messages = messages ?? ImmutableList.Empty; - this.scheduledMessages = scheduledMessages ?? ImmutableSortedSet.Empty.WithComparer(TimerFiredEventComparer.Instance); } - public static PersistentSession Create(string sessionId, IImmutableList sessionState, IImmutableList messages, ImmutableSortedSet scheduledMessages) + public static PersistentSession Create(string sessionId, IImmutableList sessionState, IImmutableList messages) { - return new PersistentSession(sessionId, sessionState, messages, scheduledMessages); + return new PersistentSession(sessionId, sessionState, messages); } public ImmutableList SessionState => this.sessionState.ToImmutableList(); public ImmutableList Messages => this.messages.ToImmutableList(); - public ImmutableSortedSet ScheduledMessages => this.scheduledMessages.ToImmutableSortedSet(TimerFiredEventComparer.Instance); } [DataContract] diff --git a/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs b/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs new file mode 100644 index 000000000..003c9d052 --- /dev/null +++ b/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs @@ -0,0 +1,146 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace DurableTask.ServiceFabric +{ + using System; + using System.Collections.Generic; + using System.Collections.Immutable; + using System.Linq; + using System.Threading.Tasks; + using DurableTask.History; + using Microsoft.ServiceFabric.Data; + using Microsoft.ServiceFabric.Data.Collections; + + class ScheduledMessageProvider : MessageProviderBase + { + readonly SessionsProvider sessionsProvider; + readonly object @lock = new object(); + + ImmutableSortedSet> inMemorySet = ImmutableSortedSet>.Empty.WithComparer(TimerFiredEventComparer.Instance); + DateTime nextActivationCheck; + + public ScheduledMessageProvider(IReliableStateManager stateManager, string storeName, SessionsProvider sessionsProvider) : base(stateManager, storeName) + { + this.sessionsProvider = sessionsProvider; + } + + public override async Task StartAsync() + { + await InitializeStore(); + + using (var tx = this.StateManager.CreateTransaction()) + { + var count = await this.Store.GetCountAsync(tx); + + if (count > 0) + { + var builder = this.inMemorySet.ToBuilder(); + + var enumerable = await this.Store.CreateEnumerableAsync(tx, EnumerationMode.Unordered); + using (var enumerator = enumerable.GetAsyncEnumerator()) + { + while (await enumerator.MoveNextAsync(this.CancellationToken)) + { + builder.Add(new Message(enumerator.Current.Key, enumerator.Current.Value)); + } + } + + this.inMemorySet = builder.ToImmutableSortedSet(); + } + } + + var nowait = ProcessScheduledMessages(); + } + + protected override void AddItemInMemory(string key, TaskMessage value) + { + lock (@lock) + { + this.inMemorySet = this.inMemorySet.Add(new Message(key, value)); + } + + //Todo: Do i need to make nextActivationCheck modifications thread safe? + var timerEvent = value.Event as TimerFiredEvent; + if (timerEvent != null && timerEvent.FireAt < this.nextActivationCheck) + { + SetWaiterForNewItems(); + } + } + + async Task ProcessScheduledMessages() + { + while (!IsStopped()) + { + var currentTime = DateTime.UtcNow; + var nextCheck = currentTime + TimeSpan.FromSeconds(1); + + var builder = this.inMemorySet.ToBuilder(); + List> activatedMessages = new List>(); + + while (builder.Count > 0) + { + var firstPendingMessage = builder.Min; + var timerEvent = firstPendingMessage.Value.Event as TimerFiredEvent; + + if (timerEvent == null) + { + throw new Exception("Internal Server Error : Ended up adding non TimerFiredEvent TaskMessage as scheduled message"); + } + + if (timerEvent.FireAt <= currentTime) + { + activatedMessages.Add(firstPendingMessage); + builder.Remove(firstPendingMessage); + } + else + { + nextCheck = timerEvent.FireAt; + break; + } + } + + if (IsStopped()) + { + break; + } + + if (activatedMessages.Count > 0) + { + var keys = activatedMessages.Select(m => m.Key); + var values = activatedMessages.Select(m => m.Value).ToList(); + + using (var tx = this.StateManager.CreateTransaction()) + { + var modifiedSessions = await this.sessionsProvider.TryAppendMessageBatchAsync(tx, values); + await this.CompleteBatchAsync(tx, keys); + await tx.CommitAsync(); + + lock (@lock) + { + this.inMemorySet = this.inMemorySet.Except(activatedMessages); + } + + foreach (var sessionId in modifiedSessions) + { + this.sessionsProvider.TryEnqueueSession(sessionId); + } + } + } + + this.nextActivationCheck = nextCheck; + await WaitForItemsAsync(this.nextActivationCheck - DateTime.UtcNow); + } + } + } +} diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 43416aabd..d4c932cde 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -28,7 +28,7 @@ public class SessionsProvider readonly IReliableStateManager stateManager; readonly CancellationTokenSource cancellationTokenSource; - readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId, null, null, null); + readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId, null, null); IReliableDictionary orchestrations; ConcurrentQueue inMemorySessionsQueue = new ConcurrentQueue(); @@ -71,70 +71,12 @@ public async Task StartAsync() } } } - - var nowait = ProcessScheduledMessages(); - } - - // Todo: Can optimize in a few other ways, for now, something that works - async Task ProcessScheduledMessages() - { - while (!this.cancellationTokenSource.IsCancellationRequested) - { - var scheduledMessageSessions = new List(); - var now = DateTime.UtcNow; - using (var txn = this.stateManager.CreateTransaction()) - { - var enumerable = await this.orchestrations.CreateEnumerableAsync(txn, EnumerationMode.Unordered); - using (var enumerator = enumerable.GetAsyncEnumerator()) - { - while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) - { - var entry = enumerator.Current; - if (entry.Value.HasScheduledMessagesDue(now)) - { - scheduledMessageSessions.Add(entry.Key); - } - } - } - } - - if (this.cancellationTokenSource.IsCancellationRequested) - { - break; - } - - foreach (var sessionId in scheduledMessageSessions) - { - using (var txn = this.stateManager.CreateTransaction()) - { - var existingValue = await this.orchestrations.TryGetValueAsync(txn, sessionId, LockMode.Update); - if (existingValue.HasValue) - { - var old = existingValue.Value; - var newValue = old.FireScheduledMessages(); - - if (old != newValue) - { - await this.orchestrations.TryUpdateAsync(txn, sessionId, newValue, old, TimeSpan.FromSeconds(4), this.cancellationTokenSource.Token); - await txn.CommitAsync(); - this.TryEnqueueSession(sessionId); - } - } - } - } - - if (this.cancellationTokenSource.IsCancellationRequested) - { - break; - } - - await Task.Delay(TimeSpan.FromMilliseconds(100)); - } } - public void Stop() + public Task StopAsync() { this.cancellationTokenSource.Cancel(); + return Task.FromResult(null); } public async Task AcceptSessionAsync(TimeSpan receiveTimeout) @@ -189,11 +131,10 @@ public List GetSessionMessages(PersistentSession session) /// public Task CompleteAndUpdateSession(ITransaction transaction, string sessionId, - OrchestrationRuntimeState newSessionState, - IList scheduledMessages) + OrchestrationRuntimeState newSessionState) { return this.orchestrations.AddOrUpdateAsync(transaction, sessionId, NewSessionFactory, - (sId, oldValue) => oldValue.CompleteMessages(newSessionState, scheduledMessages)); + (sId, oldValue) => oldValue.CompleteMessages(newSessionState)); } public async Task AppendMessageAsync(TaskMessage newMessage) @@ -220,6 +161,49 @@ await this.orchestrations.AddOrUpdateAsync(transaction, newMessage.Orchestration updateValueFactory: (ses, oldValue) => oldValue.AppendMessage(newMessage)); } + public async Task TryAppendMessageAsync(ITransaction transaction, TaskMessage newMessage) + { + ThrowIfStopped(); + + var sessionId = newMessage.OrchestrationInstance.InstanceId; + var existingValue = await this.orchestrations.TryGetValueAsync(transaction, sessionId, LockMode.Update); + if (existingValue.HasValue) + { + var newValue = existingValue.Value.AppendMessage(newMessage); + if (newValue != existingValue.Value) + { + await this.orchestrations.TryUpdateAsync(transaction, sessionId, newValue, existingValue.Value); + return true; + } + } + + return false; + } + + public async Task> TryAppendMessageBatchAsync(ITransaction transaction, IEnumerable newMessages) + { + ThrowIfStopped(); + List modifiedSessions = new List(); + + var groups = newMessages.GroupBy(m => m.OrchestrationInstance.InstanceId); + + foreach (var group in groups) + { + var existingValue = await this.orchestrations.TryGetValueAsync(transaction, group.Key, LockMode.Update); + if (existingValue.HasValue) + { + var newValue = existingValue.Value.AppendMessageBatch(group.AsEnumerable()); + if (newValue != existingValue.Value) + { + await this.orchestrations.TryUpdateAsync(transaction, group.Key, newValue, existingValue.Value); + modifiedSessions.Add(group.Key); + } + } + } + + return modifiedSessions; + } + public async Task AppendMessageBatchAsync(ITransaction transaction, IEnumerable newMessages) { ThrowIfStopped(); diff --git a/src/DurableTask.ServiceFabric/TimerFiredEventComparer.cs b/src/DurableTask.ServiceFabric/TimerFiredEventComparer.cs index 909b81344..7412142bb 100644 --- a/src/DurableTask.ServiceFabric/TimerFiredEventComparer.cs +++ b/src/DurableTask.ServiceFabric/TimerFiredEventComparer.cs @@ -17,24 +17,14 @@ namespace DurableTask.ServiceFabric using System.Collections.Generic; using DurableTask.History; - public sealed class TimerFiredEventComparer : IComparer + sealed class TimerFiredEventComparer : IComparer> { public static readonly TimerFiredEventComparer Instance = new TimerFiredEventComparer(); - public int Compare(TaskMessage first, TaskMessage second) + public int Compare(Message first, Message second) { - if (first == null) - { - throw new ArgumentNullException(nameof(first)); - } - - if (second == null) - { - throw new ArgumentNullException(nameof(second)); - } - - var firstTimer = first.Event as TimerFiredEvent; - var secondTimer = second.Event as TimerFiredEvent; + var firstTimer = first?.Value.Event as TimerFiredEvent; + var secondTimer = second?.Value.Event as TimerFiredEvent; if (firstTimer == null) { From c473386b47ebc5560e60dd9254bddadee7044c42 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 4 Oct 2016 11:43:05 -0700 Subject: [PATCH 105/210] Refactoring the SessionsProvider also to derive from common base to reduce code duplication, however not all the code is reduced because SessionsProvider works a little differently in the sense that it takes TaskMessages for Send operations and appends them to existing Session objects (compared to ActivitiesProvider which takes TaskMessages and adds them to the store). --- src/DurableTask.ServiceFabric/Message.cs | 2 +- .../MessageProviderBase.cs | 2 +- .../SessionsProvider.cs | 121 +++++++----------- 3 files changed, 46 insertions(+), 79 deletions(-) diff --git a/src/DurableTask.ServiceFabric/Message.cs b/src/DurableTask.ServiceFabric/Message.cs index 747a403f0..788568d58 100644 --- a/src/DurableTask.ServiceFabric/Message.cs +++ b/src/DurableTask.ServiceFabric/Message.cs @@ -17,7 +17,7 @@ namespace DurableTask.ServiceFabric using System.Runtime.Serialization; [DataContract] - class Message where TKey : IComparable, IEquatable + public class Message where TKey : IComparable, IEquatable { public Message(TKey key, TValue value) { diff --git a/src/DurableTask.ServiceFabric/MessageProviderBase.cs b/src/DurableTask.ServiceFabric/MessageProviderBase.cs index 54ffd147e..9302913b6 100644 --- a/src/DurableTask.ServiceFabric/MessageProviderBase.cs +++ b/src/DurableTask.ServiceFabric/MessageProviderBase.cs @@ -20,7 +20,7 @@ namespace DurableTask.ServiceFabric using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; - abstract class MessageProviderBase where TKey : IComparable, IEquatable + public abstract class MessageProviderBase where TKey : IComparable, IEquatable { readonly string storeName; readonly CancellationTokenSource cancellationTokenSource; diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index d4c932cde..c5bd7798b 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -16,67 +16,21 @@ namespace DurableTask.ServiceFabric using System; using System.Collections.Concurrent; using System.Collections.Generic; - using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; - public class SessionsProvider + public class SessionsProvider : MessageProviderBase { - readonly IReliableStateManager stateManager; - readonly CancellationTokenSource cancellationTokenSource; - readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId, null, null); - IReliableDictionary orchestrations; ConcurrentQueue inMemorySessionsQueue = new ConcurrentQueue(); ConcurrentDictionary lockedSessions = new ConcurrentDictionary(); - readonly AsyncManualResetEvent waitEvent = new AsyncManualResetEvent(); - - public SessionsProvider(IReliableStateManager stateManager) - { - if (stateManager == null) - { - throw new ArgumentNullException(nameof(stateManager)); - } - - this.stateManager = stateManager; - this.cancellationTokenSource = new CancellationTokenSource(); - } - - public async Task StartAsync() - { - this.orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); - - using (var txn = this.stateManager.CreateTransaction()) - { - var count = await this.orchestrations.GetCountAsync(txn); - - if (count > 0) - { - var enumerable = await this.orchestrations.CreateEnumerableAsync(txn, EnumerationMode.Unordered); - using (var enumerator = enumerable.GetAsyncEnumerator()) - { - while (await enumerator.MoveNextAsync(this.cancellationTokenSource.Token)) - { - var entry = enumerator.Current; - if (entry.Value.Messages.Any()) - { - this.TryEnqueueSession(entry.Key); - } - } - } - } - } - } - - public Task StopAsync() + public SessionsProvider(IReliableStateManager stateManager) : base(stateManager, Constants.OrchestrationDictionaryName) { - this.cancellationTokenSource.Cancel(); - return Task.FromResult(null); } public async Task AcceptSessionAsync(TimeSpan receiveTimeout) @@ -92,18 +46,29 @@ public async Task AcceptSessionAsync(TimeSpan receiveTimeout) { try { - using (var txn = this.stateManager.CreateTransaction()) + using (var txn = this.StateManager.CreateTransaction()) { - //Todo: TryUpdate feels more natural here than AddOrUpdateAsync, however what do we do if it fails? - var result = await this.orchestrations.AddOrUpdateAsync(txn, returnSessionId, NewSessionFactory, (sId, oldValue) => oldValue.ReceiveMessages()); - await txn.CommitAsync(); + var existingValue = await this.Store.TryGetValueAsync(txn, returnSessionId, LockMode.Update); - if (!this.lockedSessions.TryUpdate(returnSessionId, newValue:LockState.Locked, comparisonValue:LockState.InFetchQueue)) + if (existingValue.HasValue) { - throw new Exception("Internal Server Error : Unexpected to dequeue a session which was already locked before"); + var newValue = existingValue.Value.ReceiveMessages(); + if (await this.Store.TryUpdateAsync(txn, returnSessionId, newValue, existingValue.Value)) + { + await txn.CommitAsync(); + + if (!this.lockedSessions.TryUpdate(returnSessionId, newValue: LockState.Locked, comparisonValue: LockState.InFetchQueue)) + { + throw new Exception("Internal Server Error : Unexpected to dequeue a session which was already locked before"); + } + + return newValue; + } + else + { + TryEnqueueSession(returnSessionId); + } } - - return result; } } catch (TimeoutException) @@ -113,13 +78,20 @@ public async Task AcceptSessionAsync(TimeSpan receiveTimeout) } } - this.waitEvent.Reset(); - newItemsBeforeTimeout = await this.waitEvent.WaitAsync(receiveTimeout, this.cancellationTokenSource.Token); + newItemsBeforeTimeout = await WaitForItemsAsync(receiveTimeout); } return null; } + protected override void AddItemInMemory(string key, PersistentSession value) + { + if (value.Messages.Count > 0) + { + this.TryEnqueueSession(key); + } + } + public List GetSessionMessages(PersistentSession session) { return session.Messages.Where(m => m.IsReceived).Select(m => m.TaskMessage).ToList(); @@ -133,7 +105,7 @@ public Task CompleteAndUpdateSession(ITransaction transaction string sessionId, OrchestrationRuntimeState newSessionState) { - return this.orchestrations.AddOrUpdateAsync(transaction, sessionId, NewSessionFactory, + return this.Store.AddOrUpdateAsync(transaction, sessionId, NewSessionFactory, (sId, oldValue) => oldValue.CompleteMessages(newSessionState)); } @@ -142,7 +114,7 @@ public async Task AppendMessageAsync(TaskMessage newMessage) ThrowIfStopped(); await EnsureOrchestrationStoreInitialized(); - using (var txn = this.stateManager.CreateTransaction()) + using (var txn = this.StateManager.CreateTransaction()) { await this.AppendMessageAsync(txn, newMessage); await txn.CommitAsync(); @@ -156,7 +128,7 @@ public async Task AppendMessageAsync(ITransaction transaction, TaskMessage newMe ThrowIfStopped(); Func newSessionFactory = (sId) => PersistentSession.CreateWithNewMessage(sId, newMessage); - await this.orchestrations.AddOrUpdateAsync(transaction, newMessage.OrchestrationInstance.InstanceId, + await this.Store.AddOrUpdateAsync(transaction, newMessage.OrchestrationInstance.InstanceId, addValueFactory: newSessionFactory, updateValueFactory: (ses, oldValue) => oldValue.AppendMessage(newMessage)); } @@ -166,13 +138,13 @@ public async Task TryAppendMessageAsync(ITransaction transaction, TaskMess ThrowIfStopped(); var sessionId = newMessage.OrchestrationInstance.InstanceId; - var existingValue = await this.orchestrations.TryGetValueAsync(transaction, sessionId, LockMode.Update); + var existingValue = await this.Store.TryGetValueAsync(transaction, sessionId, LockMode.Update); if (existingValue.HasValue) { var newValue = existingValue.Value.AppendMessage(newMessage); if (newValue != existingValue.Value) { - await this.orchestrations.TryUpdateAsync(transaction, sessionId, newValue, existingValue.Value); + await this.Store.TryUpdateAsync(transaction, sessionId, newValue, existingValue.Value); return true; } } @@ -189,13 +161,13 @@ public async Task> TryAppendMessageBatchAsync(ITransaction transac foreach (var group in groups) { - var existingValue = await this.orchestrations.TryGetValueAsync(transaction, group.Key, LockMode.Update); + var existingValue = await this.Store.TryGetValueAsync(transaction, group.Key, LockMode.Update); if (existingValue.HasValue) { var newValue = existingValue.Value.AppendMessageBatch(group.AsEnumerable()); if (newValue != existingValue.Value) { - await this.orchestrations.TryUpdateAsync(transaction, group.Key, newValue, existingValue.Value); + await this.Store.TryUpdateAsync(transaction, group.Key, newValue, existingValue.Value); modifiedSessions.Add(group.Key); } } @@ -215,7 +187,7 @@ public async Task AppendMessageBatchAsync(ITransaction transaction, IEnumerable< Func newSessionFactory = (sId) => PersistentSession.CreateWithNewMessages(sId, groupMessages); - await this.orchestrations.AddOrUpdateAsync(transaction, group.Key, + await this.Store.AddOrUpdateAsync(transaction, group.Key, addValueFactory: newSessionFactory, updateValueFactory: (ses, oldValue) => oldValue.AppendMessageBatch(groupMessages)); } @@ -239,18 +211,18 @@ public async Task SessionExists(string sessionId) { await EnsureOrchestrationStoreInitialized(); - using (var txn = this.stateManager.CreateTransaction()) + using (var txn = this.StateManager.CreateTransaction()) { - return await this.orchestrations.ContainsKeyAsync(txn, sessionId); + return await this.Store.ContainsKeyAsync(txn, sessionId); } } async Task EnsureOrchestrationStoreInitialized() { //Workaround to avoid client sending a new message before StartAsync on service is done - if (this.orchestrations == null) + if (this.Store == null) { - this.orchestrations = await this.stateManager.GetOrAddAsync>(Constants.OrchestrationDictionaryName); + await InitializeStore(); } } @@ -259,18 +231,13 @@ public void TryEnqueueSession(string sessionId) if (this.lockedSessions.TryAdd(sessionId, LockState.InFetchQueue)) { this.inMemorySessionsQueue.Enqueue(sessionId); - this.waitEvent.Set(); + SetWaiterForNewItems(); } } public async Task DropSession(ITransaction transaction, string sessionId) { - await this.orchestrations.TryRemoveAsync(transaction, sessionId); - } - - void ThrowIfStopped() - { - this.cancellationTokenSource.Token.ThrowIfCancellationRequested(); + await this.Store.TryRemoveAsync(transaction, sessionId); } enum LockState From 4023e7dba1273ab3d896269219c7ad6ad958a576 Mon Sep 17 00:00:00 2001 From: pradeek Date: Fri, 14 Oct 2016 15:39:51 -0700 Subject: [PATCH 106/210] some cleanup of unreferenced files and changing the project references (only the order) to bring all package based references to one place. (Prepares the projects to be used as submodules) --- .../DurableTask.ServiceFabric.Test.csproj | 59 -------------- .../Properties/AssemblyInfo.cs | 36 --------- .../DurableTask.ServiceFabric.csproj | 77 ------------------- .../Properties/AssemblyInfo.cs | 36 --------- DurableTask.ServiceFabric/packages.config | 5 -- .../DurableTask.Framework.csproj | 8 +- .../DurableTask.ServiceFabric.csproj | 6 +- 7 files changed, 6 insertions(+), 221 deletions(-) delete mode 100644 DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj delete mode 100644 DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs delete mode 100644 DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj delete mode 100644 DurableTask.ServiceFabric/Properties/AssemblyInfo.cs delete mode 100644 DurableTask.ServiceFabric/packages.config diff --git a/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj b/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj deleted file mode 100644 index 98081b9f1..000000000 --- a/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj +++ /dev/null @@ -1,59 +0,0 @@ - - - - - Debug - AnyCPU - {EDC63DDB-8397-4AEC-BF54-6395B2527075} - Library - Properties - DurableTask.ServiceFabric.Test - DurableTask.ServiceFabric.Test - v4.5.2 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - {5c617b24-4902-4992-8f71-ab14f00b74a8} - DurableTask.ServiceFabric - - - - - \ No newline at end of file diff --git a/DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs b/DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs deleted file mode 100644 index 61fc9be86..000000000 --- a/DurableTask.ServiceFabric.Test/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("DurableTask.ServiceFabric.Test")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("DurableTask.ServiceFabric.Test")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("edc63ddb-8397-4aec-bf54-6395b2527075")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj deleted file mode 100644 index 914fea431..000000000 --- a/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ /dev/null @@ -1,77 +0,0 @@ - - - - - Debug - AnyCPU - {5C617B24-4902-4992-8F71-AB14F00B74A8} - Library - Properties - DurableTask.ServiceFabric - DurableTask.ServiceFabric - v4.5.2 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll - True - - - ..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll - True - - - ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.dll - True - - - ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll - True - - - - - ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\System.Fabric.dll - True - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs b/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs deleted file mode 100644 index c2c980c3e..000000000 --- a/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("DurableTask.ServiceFabric")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("DurableTask.ServiceFabric")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("5c617b24-4902-4992-8f71-ab14f00b74a8")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DurableTask.ServiceFabric/packages.config b/DurableTask.ServiceFabric/packages.config deleted file mode 100644 index 99d0248fb..000000000 --- a/DurableTask.ServiceFabric/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/DurableTask.Framework/DurableTask.Framework.csproj b/src/DurableTask.Framework/DurableTask.Framework.csproj index dbcb459a9..6e55ebedd 100644 --- a/src/DurableTask.Framework/DurableTask.Framework.csproj +++ b/src/DurableTask.Framework/DurableTask.Framework.csproj @@ -86,15 +86,15 @@ $(SolutionDir)\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll True + + $(SolutionDir)\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll + True + - - $(SolutionDir)\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll - True - diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index cbb440c22..37805de10 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -11,8 +11,6 @@ DurableTask.ServiceFabric DurableTask.ServiceFabric 512 - - true @@ -53,17 +51,17 @@ ..\..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\ServiceFabricServiceModel.dll True - False ..\..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll True - ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\System.Fabric.dll True + + From 69c849e966789a971fa0830e2f6974530fdaa1be Mon Sep 17 00:00:00 2001 From: pradeek Date: Wed, 19 Oct 2016 17:15:58 -0700 Subject: [PATCH 107/210] Adding a couple of todo comments in code. --- src/DurableTask.ServiceFabric/FabricOrchestrationService.cs | 1 + src/DurableTask.ServiceFabric/SessionsProvider.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index d168355f1..3b92cb39a 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -21,6 +21,7 @@ namespace DurableTask.ServiceFabric using DurableTask.Tracking; using Microsoft.ServiceFabric.Data; + //Todo: Create a settings class to customize interesting properties of this class like number of dispatchers... public class FabricOrchestrationService : IOrchestrationService { readonly IReliableStateManager stateManager; diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index c5bd7798b..97d839ac6 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -22,6 +22,8 @@ namespace DurableTask.ServiceFabric using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; + //Todo: Make this class internal and introduce a factory class for instantiating custom provider interfaces + // to pass to TaskHub Worker and Client public class SessionsProvider : MessageProviderBase { readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId, null, null); From 8a018b287ee7ce9e74260f3c10f5dd4865fda4ca Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 7 Nov 2016 10:48:09 -0800 Subject: [PATCH 108/210] Changes to upgrade the test application according to the latest winfab SDK. Also added a to-do to orchestration client identified while using the package. --- .../DeploymentUtil/ApplicationInfoReader.cs | 2 +- .../ApplicationParameters/Local.1Node.xml | 8 ++++++ .../{Local.xml => Local.5Node.xml} | 0 .../{Local.xml => Local.1Node.xml} | 2 +- .../PublishProfiles/Local.5Node.xml | 11 ++++++++ .../Scripts/Deploy-FabricApplication.ps1 | 28 ++++++++++++++++--- .../TestFabricApplication.sfproj | 12 ++++---- .../TestFabricApplication/packages.config | 2 +- .../FabricOrchestrationServiceClient.cs | 1 + 9 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Local.1Node.xml rename Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/{Local.xml => Local.5Node.xml} (100%) rename Test/TestFabricApplication/TestFabricApplication/PublishProfiles/{Local.xml => Local.1Node.xml} (97%) create mode 100644 Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.5Node.xml diff --git a/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/ApplicationInfoReader.cs b/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/ApplicationInfoReader.cs index 4ac4b6548..773fb3206 100644 --- a/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/ApplicationInfoReader.cs +++ b/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/ApplicationInfoReader.cs @@ -71,7 +71,7 @@ public string GetServiceName() public NameValueCollection GetApplicationParameters() { - var applicationParametersPath = Path.Combine(applicationRootPath, @"ApplicationParameters\Local.xml"); + var applicationParametersPath = Path.Combine(applicationRootPath, @"ApplicationParameters\Local.5Node.xml"); var applicationParameters = new XmlDocument(); applicationParameters.Load(applicationParametersPath); diff --git a/Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Local.1Node.xml b/Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Local.1Node.xml new file mode 100644 index 000000000..3411afa5b --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Local.1Node.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Local.xml b/Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Local.5Node.xml similarity index 100% rename from Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Local.xml rename to Test/TestFabricApplication/TestFabricApplication/ApplicationParameters/Local.5Node.xml diff --git a/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.xml b/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.1Node.xml similarity index 97% rename from Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.xml rename to Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.1Node.xml index c5cffffa3..6e1403e96 100644 --- a/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.xml +++ b/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.1Node.xml @@ -7,5 +7,5 @@ For example: --> - + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.5Node.xml b/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.5Node.xml new file mode 100644 index 000000000..f42d759c3 --- /dev/null +++ b/Test/TestFabricApplication/TestFabricApplication/PublishProfiles/Local.5Node.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/Scripts/Deploy-FabricApplication.ps1 b/Test/TestFabricApplication/TestFabricApplication/Scripts/Deploy-FabricApplication.ps1 index f3954db37..9b43f36bd 100644 --- a/Test/TestFabricApplication/TestFabricApplication/Scripts/Deploy-FabricApplication.ps1 +++ b/Test/TestFabricApplication/TestFabricApplication/Scripts/Deploy-FabricApplication.ps1 @@ -25,7 +25,7 @@ Indicates whether to unregister any unused application versions that exist after .PARAMETER OverrideUpgradeBehavior Indicates the behavior used to override the upgrade settings specified by the publish profile. -'None' indicates that the upgrade settings will not be overriden. +'None' indicates that the upgrade settings will not be overridden. 'ForceUpgrade' indicates that an upgrade will occur with default settings, regardless of what is specified in the publish profile. 'VetoUpgrade' indicates that an upgrade will not occur, regardless of what is specified in the publish profile. @@ -44,6 +44,9 @@ Switch signaling whether the package should be validated or not before deploymen .PARAMETER SecurityToken A security token for authentication to cluster management endpoints. Used for silent authentication to clusters that are protected by Azure Active Directory. +.PARAMETER CopyPackageTimeoutSec +Timeout in seconds for copying application package to image store. + .EXAMPLE . Scripts\Deploy-FabricApplication.ps1 -ApplicationPackagePath 'pkg\Debug' @@ -92,7 +95,10 @@ Param $SkipPackageValidation, [String] - $SecurityToken + $SecurityToken, + + [int] + $CopyPackageTimeoutSec ) function Read-XmlElementAsHashtable @@ -206,7 +212,14 @@ if ($IsUpgrade) $UpgradeParameters = @{ UnmonitoredAuto = $true; Force = $true } } - Publish-UpgradedServiceFabricApplication -ApplicationPackagePath $ApplicationPackagePath -ApplicationParameterFilePath $publishProfile.ApplicationParameterFile -Action $Action -UpgradeParameters $UpgradeParameters -ApplicationParameter $ApplicationParameter -UnregisterUnusedVersions:$UnregisterUnusedApplicationVersionsAfterUpgrade -ErrorAction Stop + if ($CopyPackageTimeoutSec) + { + Publish-UpgradedServiceFabricApplication -ApplicationPackagePath $ApplicationPackagePath -ApplicationParameterFilePath $publishProfile.ApplicationParameterFile -Action $Action -UpgradeParameters $UpgradeParameters -ApplicationParameter $ApplicationParameter -UnregisterUnusedVersions:$UnregisterUnusedApplicationVersionsAfterUpgrade -CopyPackageTimeoutSec $CopyPackageTimeoutSec -ErrorAction Stop + } + else + { + Publish-UpgradedServiceFabricApplication -ApplicationPackagePath $ApplicationPackagePath -ApplicationParameterFilePath $publishProfile.ApplicationParameterFile -Action $Action -UpgradeParameters $UpgradeParameters -ApplicationParameter $ApplicationParameter -UnregisterUnusedVersions:$UnregisterUnusedApplicationVersionsAfterUpgrade -ErrorAction Stop + } } else { @@ -216,5 +229,12 @@ else $Action = "Register" } - Publish-NewServiceFabricApplication -ApplicationPackagePath $ApplicationPackagePath -ApplicationParameterFilePath $publishProfile.ApplicationParameterFile -Action $Action -ApplicationParameter $ApplicationParameter -OverwriteBehavior $OverwriteBehavior -SkipPackageValidation:$SkipPackageValidation -ErrorAction Stop + if ($CopyPackageTimeoutSec) + { + Publish-NewServiceFabricApplication -ApplicationPackagePath $ApplicationPackagePath -ApplicationParameterFilePath $publishProfile.ApplicationParameterFile -Action $Action -ApplicationParameter $ApplicationParameter -OverwriteBehavior $OverwriteBehavior -SkipPackageValidation:$SkipPackageValidation -CopyPackageTimeoutSec $CopyPackageTimeoutSec -ErrorAction Stop + } + else + { + Publish-NewServiceFabricApplication -ApplicationPackagePath $ApplicationPackagePath -ApplicationParameterFilePath $publishProfile.ApplicationParameterFile -Action $Action -ApplicationParameter $ApplicationParameter -OverwriteBehavior $OverwriteBehavior -SkipPackageValidation:$SkipPackageValidation -ErrorAction Stop + } } \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/TestFabricApplication.sfproj b/Test/TestFabricApplication/TestFabricApplication/TestFabricApplication.sfproj index ddb330094..e7d8005f5 100644 --- a/Test/TestFabricApplication/TestFabricApplication/TestFabricApplication.sfproj +++ b/Test/TestFabricApplication/TestFabricApplication/TestFabricApplication.sfproj @@ -1,9 +1,9 @@  - + ca924781-ae52-45fa-a817-c39c822fb782 - 1.1 + 1.3 @@ -18,21 +18,23 @@ - + - + + + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Service Fabric Tools\Microsoft.VisualStudio.Azure.Fabric.ApplicationProject.targets - + \ No newline at end of file diff --git a/Test/TestFabricApplication/TestFabricApplication/packages.config b/Test/TestFabricApplication/TestFabricApplication/packages.config index debf3eb2f..b681b821e 100644 --- a/Test/TestFabricApplication/TestFabricApplication/packages.config +++ b/Test/TestFabricApplication/TestFabricApplication/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index 3ca9323d9..d3c038b50 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -33,6 +33,7 @@ public FabricOrchestrationServiceClient(IReliableStateManager stateManager, Sess this.instanceStore = instanceStore; } + //Todo: This should also add to instance store so that querying for status immediately will not return null. public async Task CreateTaskOrchestrationAsync(TaskMessage creationMessage) { if (!(creationMessage.Event is ExecutionStartedEvent)) From 246299fe3a7115671e4f0ee824df1b9de6615cf7 Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 7 Nov 2016 11:53:50 -0800 Subject: [PATCH 109/210] Making SessionsProvider internal (and also other provider implementations) and exposing a public factory class to get to provider interfaces. Also doing some code cleanup in test fabric application. --- .../DebugHelper/TestExecutor.cs | 51 -------------- .../TestStatefulService.cs | 16 ++--- .../TestStatefulService.csproj | 1 - .../DurableTask.ServiceFabric.csproj | 1 + .../FabricOrchestrationProviderFactory.cs | 66 +++++++++++++++++++ .../FabricOrchestrationService.cs | 2 +- .../FabricOrchestrationServiceClient.cs | 2 +- .../SessionsProvider.cs | 4 +- 8 files changed, 75 insertions(+), 68 deletions(-) delete mode 100644 Test/TestFabricApplication/TestStatefulService/DebugHelper/TestExecutor.cs create mode 100644 src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs diff --git a/Test/TestFabricApplication/TestStatefulService/DebugHelper/TestExecutor.cs b/Test/TestFabricApplication/TestStatefulService/DebugHelper/TestExecutor.cs deleted file mode 100644 index ba7cf9664..000000000 --- a/Test/TestFabricApplication/TestStatefulService/DebugHelper/TestExecutor.cs +++ /dev/null @@ -1,51 +0,0 @@ -// ---------------------------------------------------------------------------------- -// Copyright Microsoft Corporation -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ---------------------------------------------------------------------------------- - -using System; -using System.Threading; -using System.Threading.Tasks; -using DurableTask; -using TestStatefulService.TestOrchestrations; - -namespace TestStatefulService.DebugHelper -{ - class TestExecutor - { - TaskHubClient client; - CancellationTokenSource cancellationTokenSource; - - public TestExecutor(TaskHubClient client) - { - this.client = client; - this.cancellationTokenSource = new CancellationTokenSource(); - } - - public Task StartAsync() - { - var startTask = Task.Run(async () => - { - var instance = await client.CreateOrchestrationInstanceAsync(typeof(SimpleOrchestrationWithTimer), input: 37); - var state = await client.WaitForOrchestrationAsync(instance, TimeSpan.FromMinutes(10)); - var result = state.Output; - }, this.cancellationTokenSource.Token); - - return Task.FromResult(null); - } - - public Task StopAsync() - { - this.cancellationTokenSource.Cancel(); - return Task.FromResult(null); - } - } -} diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index ad53dd7df..e5f2a3fab 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -21,11 +21,10 @@ using DurableTask.ServiceFabric; using DurableTask.Test.Orchestrations.Perf; using Microsoft.ServiceFabric.Services.Communication.Runtime; +using Microsoft.ServiceFabric.Services.Remoting.Runtime; using Microsoft.ServiceFabric.Services.Runtime; using TestApplication.Common; -using TestStatefulService.DebugHelper; using TestStatefulService.TestOrchestrations; -using Microsoft.ServiceFabric.Services.Remoting.Runtime; namespace TestStatefulService { @@ -37,17 +36,12 @@ internal sealed class TestStatefulService : StatefulService, IRemoteClient TaskHubWorker worker; TaskHubClient client; ReplicaRole currentRole; - TestExecutor testExecutor; - object syncLock = new object(); - public TestStatefulService(StatefulServiceContext context) - : base(context) + public TestStatefulService(StatefulServiceContext context) : base(context) { - var instanceStore = new FabricOrchestrationInstanceStore(this.StateManager); - var sessionProvider = new SessionsProvider(this.StateManager); - this.worker = new TaskHubWorker(new FabricOrchestrationService(this.StateManager, sessionProvider, instanceStore)); - this.client = new TaskHubClient(new FabricOrchestrationServiceClient(this.StateManager, sessionProvider, instanceStore)); - this.testExecutor = new TestExecutor(this.client); + var fabricProviderFactory = new FabricOrchestrationProviderFactory(this.StateManager); + this.worker = new TaskHubWorker(fabricProviderFactory.OrchestrationService); + this.client = new TaskHubClient(fabricProviderFactory.OrchestrationServiceClient); } /// diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj index 6e2596c08..6e3be8417 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj @@ -107,7 +107,6 @@ - diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 37805de10..ee7f8c60f 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -74,6 +74,7 @@ + diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs new file mode 100644 index 000000000..111287ac0 --- /dev/null +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs @@ -0,0 +1,66 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace DurableTask.ServiceFabric +{ + using Microsoft.ServiceFabric.Data; + + public class FabricOrchestrationProviderFactory + { + readonly IReliableStateManager stateManager; + readonly object @lock; + + SessionsProvider sessionsProvider; + FabricOrchestrationService orchestrationService; + FabricOrchestrationServiceClient orchestrationClient; + FabricOrchestrationInstanceStore instanceStore; + + public FabricOrchestrationProviderFactory(IReliableStateManager stateManager) + { + this.stateManager = stateManager; + @lock = new object(); + } + + public IOrchestrationService OrchestrationService + { + get + { + this.Initialize(); + return this.orchestrationService; + } + } + + public IOrchestrationServiceClient OrchestrationServiceClient + { + get + { + this.Initialize(); + return this.orchestrationClient; + } + } + + void Initialize() + { + lock (@lock) + { + if (this.orchestrationService == null) + { + this.sessionsProvider = new SessionsProvider(this.stateManager); + this.instanceStore = new FabricOrchestrationInstanceStore(this.stateManager); + this.orchestrationService = new FabricOrchestrationService(this.stateManager, this.sessionsProvider, this.instanceStore); + this.orchestrationClient = new FabricOrchestrationServiceClient(this.stateManager, this.sessionsProvider, this.instanceStore); + } + } + } + } +} diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 3b92cb39a..3ea21ed26 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -22,7 +22,7 @@ namespace DurableTask.ServiceFabric using Microsoft.ServiceFabric.Data; //Todo: Create a settings class to customize interesting properties of this class like number of dispatchers... - public class FabricOrchestrationService : IOrchestrationService + class FabricOrchestrationService : IOrchestrationService { readonly IReliableStateManager stateManager; readonly IFabricOrchestrationServiceInstanceStore instanceStore; diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index d3c038b50..f19faa6cd 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -20,7 +20,7 @@ namespace DurableTask.ServiceFabric using DurableTask.History; using Microsoft.ServiceFabric.Data; - public class FabricOrchestrationServiceClient : IOrchestrationServiceClient + class FabricOrchestrationServiceClient : IOrchestrationServiceClient { IReliableStateManager stateManager; IFabricOrchestrationServiceInstanceStore instanceStore; diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 97d839ac6..f789da763 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -22,9 +22,7 @@ namespace DurableTask.ServiceFabric using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; - //Todo: Make this class internal and introduce a factory class for instantiating custom provider interfaces - // to pass to TaskHub Worker and Client - public class SessionsProvider : MessageProviderBase + class SessionsProvider : MessageProviderBase { readonly Func NewSessionFactory = (sId) => PersistentSession.Create(sId, null, null); From 4e40413f591d31cc5679d35886f21bab54745633 Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 7 Nov 2016 13:54:38 -0800 Subject: [PATCH 110/210] //Todo: Create a settings class to customize interesting properties of this class like number of dispatchers... --- .../TaskActivityDispatcherSettings.cs | 5 ++- .../TaskOrchestrationDispatcherSettings.cs | 5 ++- .../DurableTask.ServiceFabric.csproj | 1 + .../FabricOrchestrationProviderFactory.cs | 15 ++++++- .../FabricOrchestrationProviderSettings.cs | 45 +++++++++++++++++++ .../FabricOrchestrationService.cs | 16 ++++--- 6 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 src/DurableTask.ServiceFabric/FabricOrchestrationProviderSettings.cs diff --git a/src/DurableTask.Framework/Settings/TaskActivityDispatcherSettings.cs b/src/DurableTask.Framework/Settings/TaskActivityDispatcherSettings.cs index 432b7d758..add1bde2a 100644 --- a/src/DurableTask.Framework/Settings/TaskActivityDispatcherSettings.cs +++ b/src/DurableTask.Framework/Settings/TaskActivityDispatcherSettings.cs @@ -18,7 +18,10 @@ namespace DurableTask.Settings /// public class TaskActivityDispatcherSettings { - internal TaskActivityDispatcherSettings() + /// + /// Constructs the activity dispatcher settings with default values. + /// + public TaskActivityDispatcherSettings() { TransientErrorBackOffSecs = FrameworkConstants.ActivityTransientErrorBackOffSecs; NonTransientErrorBackOffSecs = FrameworkConstants.ActivityNonTransientErrorBackOffSecs; diff --git a/src/DurableTask.Framework/Settings/TaskOrchestrationDispatcherSettings.cs b/src/DurableTask.Framework/Settings/TaskOrchestrationDispatcherSettings.cs index a9d03b36d..bb6cdd221 100644 --- a/src/DurableTask.Framework/Settings/TaskOrchestrationDispatcherSettings.cs +++ b/src/DurableTask.Framework/Settings/TaskOrchestrationDispatcherSettings.cs @@ -18,7 +18,10 @@ namespace DurableTask.Settings /// public class TaskOrchestrationDispatcherSettings { - internal TaskOrchestrationDispatcherSettings() + /// + /// Constructs the orchestration dispatcher settings with default values. + /// + public TaskOrchestrationDispatcherSettings() { TransientErrorBackOffSecs = FrameworkConstants.OrchestrationTransientErrorBackOffSecs; NonTransientErrorBackOffSecs = FrameworkConstants.OrchestrationNonTransientErrorBackOffSecs; diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index ee7f8c60f..fd18edb57 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -75,6 +75,7 @@ + diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs index 111287ac0..930be9732 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs @@ -13,12 +13,14 @@ namespace DurableTask.ServiceFabric { + using System; using Microsoft.ServiceFabric.Data; public class FabricOrchestrationProviderFactory { readonly IReliableStateManager stateManager; readonly object @lock; + readonly FabricOrchestrationProviderSettings settings; SessionsProvider sessionsProvider; FabricOrchestrationService orchestrationService; @@ -26,9 +28,20 @@ public class FabricOrchestrationProviderFactory FabricOrchestrationInstanceStore instanceStore; public FabricOrchestrationProviderFactory(IReliableStateManager stateManager) + : this(stateManager, new FabricOrchestrationProviderSettings()) { + } + + public FabricOrchestrationProviderFactory(IReliableStateManager stateManager, FabricOrchestrationProviderSettings settings) + { + if (stateManager == null) + { + throw new ArgumentNullException(nameof(stateManager)); + } + this.stateManager = stateManager; @lock = new object(); + this.settings = settings ?? new FabricOrchestrationProviderSettings(); } public IOrchestrationService OrchestrationService @@ -57,7 +70,7 @@ void Initialize() { this.sessionsProvider = new SessionsProvider(this.stateManager); this.instanceStore = new FabricOrchestrationInstanceStore(this.stateManager); - this.orchestrationService = new FabricOrchestrationService(this.stateManager, this.sessionsProvider, this.instanceStore); + this.orchestrationService = new FabricOrchestrationService(this.stateManager, this.sessionsProvider, this.instanceStore, this.settings); this.orchestrationClient = new FabricOrchestrationServiceClient(this.stateManager, this.sessionsProvider, this.instanceStore); } } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationProviderSettings.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderSettings.cs new file mode 100644 index 000000000..ad5bd6203 --- /dev/null +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderSettings.cs @@ -0,0 +1,45 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +namespace DurableTask.ServiceFabric +{ + using DurableTask.Settings; + + public sealed class FabricOrchestrationProviderSettings + { + public FabricOrchestrationProviderSettings() + { + TaskOrchestrationDispatcherSettings = new TaskOrchestrationDispatcherSettings() + { + MaxConcurrentOrchestrations = 1000, + DispatcherCount = 1 + }; + + TaskActivityDispatcherSettings = new TaskActivityDispatcherSettings() + { + MaxConcurrentActivities = 10000, + DispatcherCount = 1 + }; + } + + /// + /// Settings to configure the Task Orchestration Dispatcher + /// + public TaskOrchestrationDispatcherSettings TaskOrchestrationDispatcherSettings { get; set; } + + /// + /// Settings to configure the Task Activity Dispatcher + /// + public TaskActivityDispatcherSettings TaskActivityDispatcherSettings { get; set; } + } +} diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index 3ea21ed26..c65262aa7 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -21,7 +21,6 @@ namespace DurableTask.ServiceFabric using DurableTask.Tracking; using Microsoft.ServiceFabric.Data; - //Todo: Create a settings class to customize interesting properties of this class like number of dispatchers... class FabricOrchestrationService : IOrchestrationService { readonly IReliableStateManager stateManager; @@ -29,8 +28,12 @@ class FabricOrchestrationService : IOrchestrationService readonly SessionsProvider orchestrationProvider; readonly ActivityProvider activitiesProvider; readonly ScheduledMessageProvider scheduledMessagesProvider; + readonly FabricOrchestrationProviderSettings settings; - public FabricOrchestrationService(IReliableStateManager stateManager, SessionsProvider orchestrationProvider, IFabricOrchestrationServiceInstanceStore instanceStore) + public FabricOrchestrationService(IReliableStateManager stateManager, + SessionsProvider orchestrationProvider, + IFabricOrchestrationServiceInstanceStore instanceStore, + FabricOrchestrationProviderSettings settings) { if (stateManager == null) { @@ -40,6 +43,7 @@ public FabricOrchestrationService(IReliableStateManager stateManager, SessionsPr this.stateManager = stateManager; this.orchestrationProvider = orchestrationProvider; this.instanceStore = instanceStore; + this.settings = settings; this.activitiesProvider = new ActivityProvider(this.stateManager, Constants.ActivitiesQueueName); this.scheduledMessagesProvider = new ScheduledMessageProvider(this.stateManager, Constants.ScheduledMessagesDictionaryName, orchestrationProvider); } @@ -127,8 +131,8 @@ public int GetDelayInSecondsAfterOnFetchException(Exception exception) return 0; } - public int TaskOrchestrationDispatcherCount => 1; - public int MaxConcurrentTaskOrchestrationWorkItems => 1000; + public int TaskOrchestrationDispatcherCount => this.settings.TaskOrchestrationDispatcherSettings.DispatcherCount; + public int MaxConcurrentTaskOrchestrationWorkItems => this.settings.TaskOrchestrationDispatcherSettings.MaxConcurrentOrchestrations; // Note: Do not rely on cancellationToken parameter to this method because the top layer does not yet implement any cancellation. public async Task LockNextTaskOrchestrationWorkItemAsync(TimeSpan receiveTimeout, CancellationToken cancellationToken) @@ -256,8 +260,8 @@ public async Task ReleaseTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkIte } } - public int TaskActivityDispatcherCount => 1; - public int MaxConcurrentTaskActivityWorkItems => 10000; + public int TaskActivityDispatcherCount => this.settings.TaskActivityDispatcherSettings.DispatcherCount; + public int MaxConcurrentTaskActivityWorkItems => this.settings.TaskActivityDispatcherSettings.MaxConcurrentActivities; // Note: Do not rely on cancellationToken parameter to this method because the top layer does not yet implement any cancellation. public async Task LockNextTaskActivityWorkItem(TimeSpan receiveTimeout, CancellationToken cancellationToken) From 378cb0881013d91f5465921744bdc689d031df24 Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 7 Nov 2016 16:20:09 -0800 Subject: [PATCH 111/210] Making another class internal that missed in commit : 246299fe3. --- src/DurableTask.ServiceFabric/MessageProviderBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DurableTask.ServiceFabric/MessageProviderBase.cs b/src/DurableTask.ServiceFabric/MessageProviderBase.cs index 9302913b6..54ffd147e 100644 --- a/src/DurableTask.ServiceFabric/MessageProviderBase.cs +++ b/src/DurableTask.ServiceFabric/MessageProviderBase.cs @@ -20,7 +20,7 @@ namespace DurableTask.ServiceFabric using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; - public abstract class MessageProviderBase where TKey : IComparable, IEquatable + abstract class MessageProviderBase where TKey : IComparable, IEquatable { readonly string storeName; readonly CancellationTokenSource cancellationTokenSource; From 8e1434a6940b5b5c631121daa1051ab55a463b71 Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 7 Nov 2016 16:27:14 -0800 Subject: [PATCH 112/210] Fixing a Todo: CreateTaskOrchestrationAsync should also add to instance store so that querying for status immediately will not return null. --- .../FabricOrchestrationServiceClient.cs | 45 ++++++++++++++++--- .../SessionsProvider.cs | 5 +-- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index f19faa6cd..2476c28a1 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -18,13 +18,14 @@ namespace DurableTask.ServiceFabric using System.Threading; using System.Threading.Tasks; using DurableTask.History; + using DurableTask.Tracking; using Microsoft.ServiceFabric.Data; class FabricOrchestrationServiceClient : IOrchestrationServiceClient { - IReliableStateManager stateManager; - IFabricOrchestrationServiceInstanceStore instanceStore; - SessionsProvider orchestrationProvider; + readonly IReliableStateManager stateManager; + readonly IFabricOrchestrationServiceInstanceStore instanceStore; + readonly SessionsProvider orchestrationProvider; public FabricOrchestrationServiceClient(IReliableStateManager stateManager, SessionsProvider orchestrationProvider, IFabricOrchestrationServiceInstanceStore instanceStore) { @@ -33,10 +34,10 @@ public FabricOrchestrationServiceClient(IReliableStateManager stateManager, Sess this.instanceStore = instanceStore; } - //Todo: This should also add to instance store so that querying for status immediately will not return null. public async Task CreateTaskOrchestrationAsync(TaskMessage creationMessage) { - if (!(creationMessage.Event is ExecutionStartedEvent)) + ExecutionStartedEvent startEvent = creationMessage.Event as ExecutionStartedEvent; + if (startEvent == null) { throw new Exception("Invalid creation message"); } @@ -49,8 +50,14 @@ public async Task CreateTaskOrchestrationAsync(TaskMessage creationMessage) throw new InvalidOperationException($"An orchestration with id '{creationMessage.OrchestrationInstance.InstanceId}' is already running."); } - await this.SendTaskOrchestrationMessageAsync(creationMessage); - ProviderEventSource.Instance.LogOrchestrationCreated(instance.InstanceId); + using (var tx = this.stateManager.CreateTransaction()) + { + await this.orchestrationProvider.AppendMessageAsync(tx, creationMessage); + await WriteExecutionStartedEventToInstanceStore(tx, startEvent); + await tx.CommitAsync(); + this.orchestrationProvider.TryEnqueueSession(creationMessage.OrchestrationInstance.InstanceId); + ProviderEventSource.Instance.LogOrchestrationCreated(instance.InstanceId); + } } public Task SendTaskOrchestrationMessageAsync(TaskMessage message) @@ -121,6 +128,30 @@ public async Task WaitForOrchestrationAsync(string instanceI return null; } + Task WriteExecutionStartedEventToInstanceStore(ITransaction tx, ExecutionStartedEvent startEvent) + { + var createdTime = DateTime.UtcNow; + var initialState = new OrchestrationState() + { + Name = startEvent.Name, + Version = startEvent.Version, + OrchestrationInstance = startEvent.OrchestrationInstance, + OrchestrationStatus = OrchestrationStatus.Pending, + Input = startEvent.Input, + Tags = startEvent.Tags, + CreatedTime = createdTime, + LastUpdatedTime = createdTime + }; + + return this.instanceStore.WriteEntitesAsync(tx, new InstanceEntityBase[] + { + new OrchestrationStateInstanceEntity() + { + State = initialState + } + }); + } + void ThrowIfInstanceStoreNotConfigured() { if (this.instanceStore == null) diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index f789da763..75115df0c 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -111,9 +111,6 @@ public Task CompleteAndUpdateSession(ITransaction transaction public async Task AppendMessageAsync(TaskMessage newMessage) { - ThrowIfStopped(); - await EnsureOrchestrationStoreInitialized(); - using (var txn = this.StateManager.CreateTransaction()) { await this.AppendMessageAsync(txn, newMessage); @@ -126,6 +123,8 @@ public async Task AppendMessageAsync(TaskMessage newMessage) public async Task AppendMessageAsync(ITransaction transaction, TaskMessage newMessage) { ThrowIfStopped(); + await EnsureOrchestrationStoreInitialized(); + Func newSessionFactory = (sId) => PersistentSession.CreateWithNewMessage(sId, newMessage); await this.Store.AddOrUpdateAsync(transaction, newMessage.OrchestrationInstance.InstanceId, From aaa5b50a51d5ac9be6e2c2048429dbad17c7580e Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 7 Nov 2016 16:55:12 -0800 Subject: [PATCH 113/210] Sample showing customizing the orchestrator settings in test application. --- .../TestStatefulService/TestStatefulService.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index e5f2a3fab..c3f1af775 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -39,7 +39,11 @@ internal sealed class TestStatefulService : StatefulService, IRemoteClient public TestStatefulService(StatefulServiceContext context) : base(context) { - var fabricProviderFactory = new FabricOrchestrationProviderFactory(this.StateManager); + var settings = new FabricOrchestrationProviderSettings(); + settings.TaskOrchestrationDispatcherSettings.DispatcherCount = 5; + settings.TaskActivityDispatcherSettings.DispatcherCount = 5; + + var fabricProviderFactory = new FabricOrchestrationProviderFactory(this.StateManager, settings); this.worker = new TaskHubWorker(fabricProviderFactory.OrchestrationService); this.client = new TaskHubClient(fabricProviderFactory.OrchestrationServiceClient); } From 9aa48c714c71e5f4c56ea6db986c9083c97e178a Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 18 Oct 2016 19:03:43 -0700 Subject: [PATCH 114/210] Changes to create nupkg files from Visual Studio build. This extension : "https://visualstudiogallery.msdn.microsoft.com/fbe9b9b8-34ae-47b5-a751-cb71a16f7e96" is a pre-req. --- DurableTask.sln | 9 +++++ README.md | 2 ++ nuproj/DurableTask/DurableTask.nuproj | 47 +++++++++++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 nuproj/DurableTask/DurableTask.nuproj diff --git a/DurableTask.sln b/DurableTask.sln index 9dc3b4c41..214671c65 100644 --- a/DurableTask.sln +++ b/DurableTask.sln @@ -35,6 +35,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.Samples.Tests", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.Test.Orchestrations", "Test\DurableTask.Test.Orchestrations\DurableTask.Test.Orchestrations.csproj", "{2BC2A5AD-4200-41B9-A034-332BB1D7187B}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuproj", "nuproj", "{E9D6C76F-4F66-49CE-BA5A-F0B355863622}" +EndProject +Project("{FF286327-C783-4F7A-AB73-9BCBAD0D4460}") = "DurableTask", "nuproj\DurableTask\DurableTask.nuproj", "{68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -69,6 +73,10 @@ Global {2BC2A5AD-4200-41B9-A034-332BB1D7187B}.Debug|Any CPU.Build.0 = Debug|Any CPU {2BC2A5AD-4200-41B9-A034-332BB1D7187B}.Release|Any CPU.ActiveCfg = Release|Any CPU {2BC2A5AD-4200-41B9-A034-332BB1D7187B}.Release|Any CPU.Build.0 = Release|Any CPU + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -81,6 +89,7 @@ Global {96980359-8003-4500-B97B-949A7FE01F31} = {95C69A06-7F62-4652-A480-207B614C2869} {1F20B608-0206-4B58-8C0B-CB7430A880FD} = {95C69A06-7F62-4652-A480-207B614C2869} {2BC2A5AD-4200-41B9-A034-332BB1D7187B} = {95C69A06-7F62-4652-A480-207B614C2869} + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80} = {E9D6C76F-4F66-49CE-BA5A-F0B355863622} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EnterpriseLibraryConfigurationToolBinariesPath = packages\TransientFaultHandling.Core.5.1.1209.1\lib\NET4 diff --git a/README.md b/README.md index e53c81e38..14672274a 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ To run unit tests, you must specify your Service Bus connection string for the t The associated wiki contains more details about the framework: https://github.com/Azure/durabletask/wiki +To load nuproj files successfully in Visual Studio, this extension is required: https://visualstudiogallery.msdn.microsoft.com/fbe9b9b8-34ae-47b5-a751-cb71a16f7e96 + TODO We could have spent a lot of time cleaning up the code and teasing apart various layers but we opted for shipping this earlier and cleaning up post-commit. Consequently there are a lot of TODOs :) diff --git a/nuproj/DurableTask/DurableTask.nuproj b/nuproj/DurableTask/DurableTask.nuproj new file mode 100644 index 000000000..e85fff998 --- /dev/null +++ b/nuproj/DurableTask/DurableTask.nuproj @@ -0,0 +1,47 @@ + + + + + Debug + AnyCPU + + + Release + AnyCPU + + + + + + + 68e5007e-2e0a-4b74-be1e-56ca0e3d4e80 + + + $(MSBuildExtensionsPath)\NuProj\ + + + + DurableTask + 2.0.4-alpha + Durable Task Framework + affandar;siport + affandar;siport + Framework for writing code workflows in C#. + +Release notes for this release: +https://github.com/azure/durabletask/releases/tag/2.0.4-alpha + + This package provides a C# based durable Task framework for writing long running applications. + +It is built from an OSS version of https://www.nuget.org/packages/ServiceBus.DurableTask. + + + + https://github.com/azure/durabletask + https://github.com/azure/durabletask/blob/vnext/LICENSE + Copyright 2013 + en-US + ServiceBus Service Bus Azure Task Durable Orchestration Workflow Activity Reliable + + + \ No newline at end of file From 6d4c087a855de37406982a66bf8d6c5ee466c6b0 Mon Sep 17 00:00:00 2001 From: pradeek Date: Tue, 18 Oct 2016 19:52:57 -0700 Subject: [PATCH 115/210] Changes to generate service fabric nuget package. --- DurableTask.ServiceFabric.sln | 24 +++++++++++ .../DurableTask.ServiceFabric.nuproj | 43 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj diff --git a/DurableTask.ServiceFabric.sln b/DurableTask.ServiceFabric.sln index c70133f72..77a21c16c 100644 --- a/DurableTask.ServiceFabric.sln +++ b/DurableTask.ServiceFabric.sln @@ -40,6 +40,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.ServiceFabric.S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.ServiceFabric.UnitTests", "Test\DurableTask.ServiceFabric.UnitTests\DurableTask.ServiceFabric.UnitTests.csproj", "{31C9C932-6376-46D4-A68A-A0A7F2726D38}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuproj", "nuproj", "{7FD169C2-680D-4B79-908B-6BF0B2FAA576}" +EndProject +Project("{FF286327-C783-4F7A-AB73-9BCBAD0D4460}") = "DurableTask.ServiceFabric", "nuproj\DurableTask.ServiceFabric\DurableTask.ServiceFabric.nuproj", "{33D8EE20-43D5-4D8E-8BEC-36914AE49657}" +EndProject +Project("{FF286327-C783-4F7A-AB73-9BCBAD0D4460}") = "DurableTask", "nuproj\DurableTask\DurableTask.nuproj", "{68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -140,6 +146,22 @@ Global {31C9C932-6376-46D4-A68A-A0A7F2726D38}.Release|Any CPU.Build.0 = Release|Any CPU {31C9C932-6376-46D4-A68A-A0A7F2726D38}.Release|x64.ActiveCfg = Release|Any CPU {31C9C932-6376-46D4-A68A-A0A7F2726D38}.Release|x64.Build.0 = Release|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|x64.ActiveCfg = Debug|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|x64.Build.0 = Debug|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|Any CPU.ActiveCfg = Release|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|Any CPU.Build.0 = Release|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|x64.ActiveCfg = Release|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|x64.Build.0 = Release|Any CPU + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|x64.ActiveCfg = Debug|Any CPU + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|x64.Build.0 = Debug|Any CPU + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|Any CPU.Build.0 = Release|Any CPU + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|x64.ActiveCfg = Release|Any CPU + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -158,6 +180,8 @@ Global {2BC2A5AD-4200-41B9-A034-332BB1D7187B} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} {BE4624F3-E565-428F-9EED-E6847530746A} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} {31C9C932-6376-46D4-A68A-A0A7F2726D38} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} + {33D8EE20-43D5-4D8E-8BEC-36914AE49657} = {7FD169C2-680D-4B79-908B-6BF0B2FAA576} + {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80} = {7FD169C2-680D-4B79-908B-6BF0B2FAA576} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EnterpriseLibraryConfigurationToolBinariesPath = packages\TransientFaultHandling.Core.5.1.1209.1\lib\NET4 diff --git a/nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj b/nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj new file mode 100644 index 000000000..044f8b2ef --- /dev/null +++ b/nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj @@ -0,0 +1,43 @@ + + + + + Debug + AnyCPU + + + Release + AnyCPU + + + + + + + + 33d8ee20-43d5-4d8e-8bec-36914ae49657 + + + $(MSBuildExtensionsPath)\NuProj\ + + + + DurableTask.ServiceFabric + 0.0.1-alpha + DurableTask.ServiceFabric + pradeek + pradeek + Service fabric based storage provider for Durable Task Framework. + Service fabric based storage provider for Durable Task Framework. + + + + + + + Copyright © 2016 + ServiceFabric Azure Task Durable Orchestration Workflow Activity Reliable + false + + + \ No newline at end of file From 7c4fd477d1e4cbe761b6689eabb6ffec90e07725 Mon Sep 17 00:00:00 2001 From: pradeek Date: Wed, 19 Oct 2016 10:37:16 -0700 Subject: [PATCH 116/210] Some code review comments - moving the nuproj into a top level folder named 'build', also reverting the changes to solution file and readme because not everyone using the solution should need dependency on VS Extension. --- DurableTask.sln | 9 --------- README.md | 2 -- {nuproj => build/nuproj}/DurableTask/DurableTask.nuproj | 0 3 files changed, 11 deletions(-) rename {nuproj => build/nuproj}/DurableTask/DurableTask.nuproj (100%) diff --git a/DurableTask.sln b/DurableTask.sln index 214671c65..9dc3b4c41 100644 --- a/DurableTask.sln +++ b/DurableTask.sln @@ -35,10 +35,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.Samples.Tests", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.Test.Orchestrations", "Test\DurableTask.Test.Orchestrations\DurableTask.Test.Orchestrations.csproj", "{2BC2A5AD-4200-41B9-A034-332BB1D7187B}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuproj", "nuproj", "{E9D6C76F-4F66-49CE-BA5A-F0B355863622}" -EndProject -Project("{FF286327-C783-4F7A-AB73-9BCBAD0D4460}") = "DurableTask", "nuproj\DurableTask\DurableTask.nuproj", "{68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -73,10 +69,6 @@ Global {2BC2A5AD-4200-41B9-A034-332BB1D7187B}.Debug|Any CPU.Build.0 = Debug|Any CPU {2BC2A5AD-4200-41B9-A034-332BB1D7187B}.Release|Any CPU.ActiveCfg = Release|Any CPU {2BC2A5AD-4200-41B9-A034-332BB1D7187B}.Release|Any CPU.Build.0 = Release|Any CPU - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|Any CPU.Build.0 = Debug|Any CPU - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|Any CPU.ActiveCfg = Release|Any CPU - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -89,7 +81,6 @@ Global {96980359-8003-4500-B97B-949A7FE01F31} = {95C69A06-7F62-4652-A480-207B614C2869} {1F20B608-0206-4B58-8C0B-CB7430A880FD} = {95C69A06-7F62-4652-A480-207B614C2869} {2BC2A5AD-4200-41B9-A034-332BB1D7187B} = {95C69A06-7F62-4652-A480-207B614C2869} - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80} = {E9D6C76F-4F66-49CE-BA5A-F0B355863622} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EnterpriseLibraryConfigurationToolBinariesPath = packages\TransientFaultHandling.Core.5.1.1209.1\lib\NET4 diff --git a/README.md b/README.md index 14672274a..e53c81e38 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,6 @@ To run unit tests, you must specify your Service Bus connection string for the t The associated wiki contains more details about the framework: https://github.com/Azure/durabletask/wiki -To load nuproj files successfully in Visual Studio, this extension is required: https://visualstudiogallery.msdn.microsoft.com/fbe9b9b8-34ae-47b5-a751-cb71a16f7e96 - TODO We could have spent a lot of time cleaning up the code and teasing apart various layers but we opted for shipping this earlier and cleaning up post-commit. Consequently there are a lot of TODOs :) diff --git a/nuproj/DurableTask/DurableTask.nuproj b/build/nuproj/DurableTask/DurableTask.nuproj similarity index 100% rename from nuproj/DurableTask/DurableTask.nuproj rename to build/nuproj/DurableTask/DurableTask.nuproj From f4ee66d178c6d6c1a8ef3dada5923a49be226234 Mon Sep 17 00:00:00 2001 From: pradeek Date: Wed, 19 Oct 2016 10:37:16 -0700 Subject: [PATCH 117/210] Fixing the relative path of project since the folder structure changed. --- build/nuproj/DurableTask/DurableTask.nuproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/nuproj/DurableTask/DurableTask.nuproj b/build/nuproj/DurableTask/DurableTask.nuproj index e85fff998..e698a0243 100644 --- a/build/nuproj/DurableTask/DurableTask.nuproj +++ b/build/nuproj/DurableTask/DurableTask.nuproj @@ -11,7 +11,7 @@ - + 68e5007e-2e0a-4b74-be1e-56ca0e3d4e80 From 8a35f59a63eea239d483bfd3d1bdebb8f1aa13bc Mon Sep 17 00:00:00 2001 From: pradeek Date: Wed, 19 Oct 2016 10:37:16 -0700 Subject: [PATCH 118/210] Rearranging the files according to the changed structure. --- DurableTask.ServiceFabric.sln | 25 +++++++++++-------- .../DurableTask.ServiceFabric.nuproj | 2 +- .../DurableTask.ServiceFabric.csproj | 2 +- 3 files changed, 16 insertions(+), 13 deletions(-) rename {nuproj => build/nuproj}/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj (94%) diff --git a/DurableTask.ServiceFabric.sln b/DurableTask.ServiceFabric.sln index 77a21c16c..ee44bd4d8 100644 --- a/DurableTask.ServiceFabric.sln +++ b/DurableTask.ServiceFabric.sln @@ -42,9 +42,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.ServiceFabric.U EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuproj", "nuproj", "{7FD169C2-680D-4B79-908B-6BF0B2FAA576}" EndProject -Project("{FF286327-C783-4F7A-AB73-9BCBAD0D4460}") = "DurableTask.ServiceFabric", "nuproj\DurableTask.ServiceFabric\DurableTask.ServiceFabric.nuproj", "{33D8EE20-43D5-4D8E-8BEC-36914AE49657}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{E524ABFA-9845-4D18-8B35-26C21320CC9C}" EndProject -Project("{FF286327-C783-4F7A-AB73-9BCBAD0D4460}") = "DurableTask", "nuproj\DurableTask\DurableTask.nuproj", "{68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}" +Project("{FF286327-C783-4F7A-AB73-9BCBAD0D4460}") = "DurableTask", "build\nuproj\DurableTask\DurableTask.nuproj", "{68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}" +EndProject +Project("{FF286327-C783-4F7A-AB73-9BCBAD0D4460}") = "DurableTask.ServiceFabric", "build\nuproj\DurableTask.ServiceFabric\DurableTask.ServiceFabric.nuproj", "{33D8EE20-43D5-4D8E-8BEC-36914AE49657}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -146,14 +148,6 @@ Global {31C9C932-6376-46D4-A68A-A0A7F2726D38}.Release|Any CPU.Build.0 = Release|Any CPU {31C9C932-6376-46D4-A68A-A0A7F2726D38}.Release|x64.ActiveCfg = Release|Any CPU {31C9C932-6376-46D4-A68A-A0A7F2726D38}.Release|x64.Build.0 = Release|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|Any CPU.Build.0 = Debug|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|x64.ActiveCfg = Debug|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|x64.Build.0 = Debug|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|Any CPU.ActiveCfg = Release|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|Any CPU.Build.0 = Release|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|x64.ActiveCfg = Release|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|x64.Build.0 = Release|Any CPU {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|Any CPU.Build.0 = Debug|Any CPU {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -162,6 +156,14 @@ Global {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|Any CPU.Build.0 = Release|Any CPU {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|x64.ActiveCfg = Release|Any CPU {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|x64.Build.0 = Release|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|Any CPU.Build.0 = Debug|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|x64.ActiveCfg = Debug|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|x64.Build.0 = Debug|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|Any CPU.ActiveCfg = Release|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|Any CPU.Build.0 = Release|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|x64.ActiveCfg = Release|Any CPU + {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -180,8 +182,9 @@ Global {2BC2A5AD-4200-41B9-A034-332BB1D7187B} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} {BE4624F3-E565-428F-9EED-E6847530746A} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} {31C9C932-6376-46D4-A68A-A0A7F2726D38} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} - {33D8EE20-43D5-4D8E-8BEC-36914AE49657} = {7FD169C2-680D-4B79-908B-6BF0B2FAA576} + {7FD169C2-680D-4B79-908B-6BF0B2FAA576} = {E524ABFA-9845-4D18-8B35-26C21320CC9C} {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80} = {7FD169C2-680D-4B79-908B-6BF0B2FAA576} + {33D8EE20-43D5-4D8E-8BEC-36914AE49657} = {7FD169C2-680D-4B79-908B-6BF0B2FAA576} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EnterpriseLibraryConfigurationToolBinariesPath = packages\TransientFaultHandling.Core.5.1.1209.1\lib\NET4 diff --git a/nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj b/build/nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj similarity index 94% rename from nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj rename to build/nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj index 044f8b2ef..e09723dcf 100644 --- a/nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj +++ b/build/nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj @@ -11,7 +11,7 @@ - + diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index fd18edb57..69f5930ec 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -105,7 +105,7 @@ {6f5d2ead-726d-4fe5-a575-aeb96d1cce37} - DurableTaskFramework + DurableTask.Framework From 9f1d18c0d3d6a0ae236d44cd0f7bfdd618affe1a Mon Sep 17 00:00:00 2001 From: pradeek Date: Wed, 19 Oct 2016 14:14:22 -0700 Subject: [PATCH 119/210] cleaning up package and project references. --- .../DurableTask.Framework.csproj | 31 +++---------------- src/DurableTask.Framework/packages.config | 11 ++----- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/src/DurableTask.Framework/DurableTask.Framework.csproj b/src/DurableTask.Framework/DurableTask.Framework.csproj index 6e55ebedd..cd0994463 100644 --- a/src/DurableTask.Framework/DurableTask.Framework.csproj +++ b/src/DurableTask.Framework/DurableTask.Framework.csproj @@ -11,7 +11,7 @@ DurableTask DurableTaskFx 512 - ..\ + ..\..\ true @@ -46,38 +46,15 @@ sign.snk - - False + $(SolutionDir)\packages\ImpromptuInterface.6.2.2\lib\net40\ImpromptuInterface.dll - - - $(SolutionDir)\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll - True - - - $(SolutionDir)\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll True - - $(SolutionDir)\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll - True - - - $(SolutionDir)\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll - True - - - False + $(SolutionDir)\packages\WindowsAzure.ServiceBus.3.1.7\lib\net45-full\Microsoft.ServiceBus.dll True - - False - $(SolutionDir)\packages\Microsoft.WindowsAzure.ConfigurationManager.3.2.1\lib\net40\Microsoft.WindowsAzure.Configuration.dll - True - - - False + $(SolutionDir)\packages\WindowsAzure.Storage.7.0.0\lib\net40\Microsoft.WindowsAzure.Storage.dll True diff --git a/src/DurableTask.Framework/packages.config b/src/DurableTask.Framework/packages.config index c227882b8..4f92b1cc2 100644 --- a/src/DurableTask.Framework/packages.config +++ b/src/DurableTask.Framework/packages.config @@ -1,14 +1,7 @@  - - - - - - - - - + + \ No newline at end of file From 6fdc59f2d71465215935d1e54a21af283871594d Mon Sep 17 00:00:00 2001 From: pradeek Date: Wed, 19 Oct 2016 14:24:09 -0700 Subject: [PATCH 120/210] Fixing the package references and project references. --- .../DurableTask.ServiceFabric.csproj | 31 ++++++++++++------- src/DurableTask.ServiceFabric/packages.config | 8 ++--- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 69f5930ec..140db12ee 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -10,6 +10,7 @@ Properties DurableTask.ServiceFabric DurableTask.ServiceFabric + ..\..\ 512 @@ -31,37 +32,45 @@ - ..\..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll + $(SolutionDir)\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll True - ..\..\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll + $(SolutionDir)\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.Interfaces.dll + True + + + $(SolutionDir)\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.dll + True + + + $(SolutionDir)\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\Microsoft.ServiceFabric.Internal.Strings.dll True - ..\..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\Microsoft.ServiceFabric.Services.dll + $(SolutionDir)\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\Microsoft.ServiceFabric.Services.dll True False - ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + $(SolutionDir)\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll True - ..\..\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\ServiceFabricServiceModel.dll + $(SolutionDir)\packages\Microsoft.ServiceFabric.Services.2.1.163\lib\net45\ServiceFabricServiceModel.dll True + False - ..\..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + $(SolutionDir)\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll True + - ..\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\System.Fabric.dll + $(SolutionDir)\packages\Microsoft.ServiceFabric.5.1.163\lib\net45\System.Fabric.dll True - - @@ -98,9 +107,7 @@ - - Designer - + diff --git a/src/DurableTask.ServiceFabric/packages.config b/src/DurableTask.ServiceFabric/packages.config index d2630a644..9f09bb9bd 100644 --- a/src/DurableTask.ServiceFabric/packages.config +++ b/src/DurableTask.ServiceFabric/packages.config @@ -1,8 +1,8 @@  - - - - + + + + \ No newline at end of file From 9ef39df4d66cadeb19a76218565630336baf01d3 Mon Sep 17 00:00:00 2001 From: pradeek Date: Wed, 19 Oct 2016 14:37:08 -0700 Subject: [PATCH 121/210] More cleanup. --- src/DurableTask.Framework/DurableTask.Framework.csproj | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/DurableTask.Framework/DurableTask.Framework.csproj b/src/DurableTask.Framework/DurableTask.Framework.csproj index cd0994463..24451766b 100644 --- a/src/DurableTask.Framework/DurableTask.Framework.csproj +++ b/src/DurableTask.Framework/DurableTask.Framework.csproj @@ -63,20 +63,11 @@ $(SolutionDir)\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll True - - $(SolutionDir)\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll - True - - - - - - From 36244d4d795e6d05a85c61c1d50a4538cd53d18a Mon Sep 17 00:00:00 2001 From: pradeek Date: Wed, 19 Oct 2016 14:55:53 -0700 Subject: [PATCH 122/210] Checking in a nuspec file as there were issues with generating package from nuproj file. --- .../DurableTask.Framework.nuspec | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/DurableTask.Framework/DurableTask.Framework.nuspec diff --git a/src/DurableTask.Framework/DurableTask.Framework.nuspec b/src/DurableTask.Framework/DurableTask.Framework.nuspec new file mode 100644 index 000000000..a951c7212 --- /dev/null +++ b/src/DurableTask.Framework/DurableTask.Framework.nuspec @@ -0,0 +1,37 @@ + + + + DurableTask + 2.0.4-alpha + Durable Task Framework + affandar;siport + affandar;siport + https://github.com/azure/durabletask/blob/vnext/LICENSE + https://github.com/azure/durabletask + false + This package provides a C# based durable Task framework for writing long running applications. + +It is built from an OSS version of https://www.nuget.org/packages/ServiceBus.DurableTask. + + Framework for writing code workflows in C#. + +Release notes for this release: +https://github.com/azure/durabletask/releases/tag/2.0.4-alpha + + Copyright 2013 + ServiceBus Service Bus Azure Task Durable Orchestration Workflow Activity Reliable + + + + + + + + + + + + + + + \ No newline at end of file From 40bfea49b451903d4c753152c5ab843378d6bd0a Mon Sep 17 00:00:00 2001 From: pradeek Date: Mon, 7 Nov 2016 18:03:45 -0800 Subject: [PATCH 123/210] A few changes: - Making all classes internal except which are necessary. (Use InternalsVisibleTo for unit tests) - Adding documentation files and nuspec files to be able to generate nuget packages using 'nuget pack' - Removing the nuproj files from solution (will delete them from source later). - Adding xml documentation to all public classes. - Updating the versions in nuspec files since there are API changes. - Making changes to avoid warnings about IDisposable --- DurableTask.ServiceFabric.sln | 27 ----------------- .../DurableTask.Framework.csproj | 1 + .../DurableTask.Framework.nuspec | 2 +- .../AsyncManualResetEvent.cs | 2 +- .../DurableTask.ServiceFabric.csproj | 3 ++ .../DurableTask.ServiceFabric.nuspec | 30 +++++++++++++++++++ .../FabricOrchestrationInstanceStore.cs | 7 +++-- .../FabricOrchestrationProviderFactory.cs | 20 +++++++++++++ .../FabricOrchestrationProviderSettings.cs | 8 +++++ ...FabricOrchestrationServiceInstanceStore.cs | 4 ++- src/DurableTask.ServiceFabric/Message.cs | 2 +- .../MessageProviderBase.cs | 7 +++-- .../PersistentSession.api.cs | 2 +- .../PersistentSession.cs | 4 +-- .../Properties/AssemblyInfo.cs | 2 ++ 15 files changed, 81 insertions(+), 40 deletions(-) create mode 100644 src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec diff --git a/DurableTask.ServiceFabric.sln b/DurableTask.ServiceFabric.sln index ee44bd4d8..c70133f72 100644 --- a/DurableTask.ServiceFabric.sln +++ b/DurableTask.ServiceFabric.sln @@ -40,14 +40,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.ServiceFabric.S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.ServiceFabric.UnitTests", "Test\DurableTask.ServiceFabric.UnitTests\DurableTask.ServiceFabric.UnitTests.csproj", "{31C9C932-6376-46D4-A68A-A0A7F2726D38}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuproj", "nuproj", "{7FD169C2-680D-4B79-908B-6BF0B2FAA576}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{E524ABFA-9845-4D18-8B35-26C21320CC9C}" -EndProject -Project("{FF286327-C783-4F7A-AB73-9BCBAD0D4460}") = "DurableTask", "build\nuproj\DurableTask\DurableTask.nuproj", "{68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}" -EndProject -Project("{FF286327-C783-4F7A-AB73-9BCBAD0D4460}") = "DurableTask.ServiceFabric", "build\nuproj\DurableTask.ServiceFabric\DurableTask.ServiceFabric.nuproj", "{33D8EE20-43D5-4D8E-8BEC-36914AE49657}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -148,22 +140,6 @@ Global {31C9C932-6376-46D4-A68A-A0A7F2726D38}.Release|Any CPU.Build.0 = Release|Any CPU {31C9C932-6376-46D4-A68A-A0A7F2726D38}.Release|x64.ActiveCfg = Release|Any CPU {31C9C932-6376-46D4-A68A-A0A7F2726D38}.Release|x64.Build.0 = Release|Any CPU - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|Any CPU.Build.0 = Debug|Any CPU - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|x64.ActiveCfg = Debug|Any CPU - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Debug|x64.Build.0 = Debug|Any CPU - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|Any CPU.ActiveCfg = Release|Any CPU - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|Any CPU.Build.0 = Release|Any CPU - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|x64.ActiveCfg = Release|Any CPU - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80}.Release|x64.Build.0 = Release|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|Any CPU.Build.0 = Debug|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|x64.ActiveCfg = Debug|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Debug|x64.Build.0 = Debug|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|Any CPU.ActiveCfg = Release|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|Any CPU.Build.0 = Release|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|x64.ActiveCfg = Release|Any CPU - {33D8EE20-43D5-4D8E-8BEC-36914AE49657}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -182,9 +158,6 @@ Global {2BC2A5AD-4200-41B9-A034-332BB1D7187B} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} {BE4624F3-E565-428F-9EED-E6847530746A} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} {31C9C932-6376-46D4-A68A-A0A7F2726D38} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} - {7FD169C2-680D-4B79-908B-6BF0B2FAA576} = {E524ABFA-9845-4D18-8B35-26C21320CC9C} - {68E5007E-2E0A-4B74-BE1E-56CA0E3D4E80} = {7FD169C2-680D-4B79-908B-6BF0B2FAA576} - {33D8EE20-43D5-4D8E-8BEC-36914AE49657} = {7FD169C2-680D-4B79-908B-6BF0B2FAA576} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EnterpriseLibraryConfigurationToolBinariesPath = packages\TransientFaultHandling.Core.5.1.1209.1\lib\NET4 diff --git a/src/DurableTask.Framework/DurableTask.Framework.csproj b/src/DurableTask.Framework/DurableTask.Framework.csproj index 24451766b..525c4ae11 100644 --- a/src/DurableTask.Framework/DurableTask.Framework.csproj +++ b/src/DurableTask.Framework/DurableTask.Framework.csproj @@ -203,6 +203,7 @@ + Designer diff --git a/src/DurableTask.Framework/DurableTask.Framework.nuspec b/src/DurableTask.Framework/DurableTask.Framework.nuspec index a951c7212..81e9255fa 100644 --- a/src/DurableTask.Framework/DurableTask.Framework.nuspec +++ b/src/DurableTask.Framework/DurableTask.Framework.nuspec @@ -2,7 +2,7 @@ DurableTask - 2.0.4-alpha + 2.0.4-alpha2 Durable Task Framework affandar;siport affandar;siport diff --git a/src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs b/src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs index c23fc3b33..36cdf3844 100644 --- a/src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs +++ b/src/DurableTask.ServiceFabric/AsyncManualResetEvent.cs @@ -17,7 +17,7 @@ namespace DurableTask.ServiceFabric using System.Threading; using System.Threading.Tasks; - public sealed class AsyncManualResetEvent + sealed class AsyncManualResetEvent { TaskCompletionSource tcs; diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 140db12ee..691207135 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -21,6 +21,7 @@ DEBUG;TRACE prompt 4 + $(OutputPath)$(AssemblyName).xml pdbonly @@ -29,6 +30,7 @@ TRACE prompt 4 + $(OutputPath)$(AssemblyName).xml @@ -107,6 +109,7 @@ + diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec new file mode 100644 index 000000000..ebb96960d --- /dev/null +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec @@ -0,0 +1,30 @@ + + + + DurableTask.ServiceFabric + 0.0.1-alpha2 + DurableTask.ServiceFabric + pradeek + pradeek + false + Service fabric based storage provider for Durable Task Framework. + Service fabric based storage provider for Durable Task Framework. + Copyright © 2016 + ServiceFabric Azure Task Durable Orchestration Workflow Activity Reliable + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs index 4d51f9852..e43f39746 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs @@ -25,18 +25,18 @@ namespace DurableTask.ServiceFabric // - Support for querying state across executions (makes sense only after ContinuedAsNew is supported) // - Support writing multiple state events for a given orchestration instance/execution (?) // - Support writing/querying/purging history events - public class FabricOrchestrationInstanceStore : IFabricOrchestrationServiceInstanceStore + class FabricOrchestrationInstanceStore : IFabricOrchestrationServiceInstanceStore { const string TimeFormatString = "yyyy-MM-dd-HH"; const string TimeFormatStringPrefix = "yyyy-MM-dd-"; readonly IReliableStateManager stateManager; - readonly CancellationTokenSource cancellationTokenSource; + + CancellationTokenSource cancellationTokenSource; IReliableDictionary instanceStore; public FabricOrchestrationInstanceStore(IReliableStateManager stateManager) { this.stateManager = stateManager; - this.cancellationTokenSource = new CancellationTokenSource(); } public async Task InitializeStoreAsync(bool recreate) @@ -49,6 +49,7 @@ public async Task InitializeStoreAsync(bool recreate) public async Task StartAsync() { + this.cancellationTokenSource = new CancellationTokenSource(); this.instanceStore = await this.GetOrAddInstanceStoreDictionary(); var nowait = CleanupDayOldDictionaries(); } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs index 930be9732..82c4a8bfe 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs @@ -16,6 +16,11 @@ namespace DurableTask.ServiceFabric using System; using Microsoft.ServiceFabric.Data; + /// + /// Factory to create instances of a service fabric based store provider implementations + /// for and + /// to be used in constructing and . + /// public class FabricOrchestrationProviderFactory { readonly IReliableStateManager stateManager; @@ -27,11 +32,20 @@ public class FabricOrchestrationProviderFactory FabricOrchestrationServiceClient orchestrationClient; FabricOrchestrationInstanceStore instanceStore; + /// + /// Constructor that uses default . + /// + /// Reliable state manager instance. Comes from service fabric stateful service implementation. public FabricOrchestrationProviderFactory(IReliableStateManager stateManager) : this(stateManager, new FabricOrchestrationProviderSettings()) { } + /// + /// Constructor that takes the custom . + /// + /// Reliable state manager instance. Comes from service fabric stateful service implementation. + /// Settings to be used for the provider. Refer to for documentation about specific settings. public FabricOrchestrationProviderFactory(IReliableStateManager stateManager, FabricOrchestrationProviderSettings settings) { if (stateManager == null) @@ -44,6 +58,9 @@ public FabricOrchestrationProviderFactory(IReliableStateManager stateManager, Fa this.settings = settings ?? new FabricOrchestrationProviderSettings(); } + /// + /// instance that can be used for constructing . + /// public IOrchestrationService OrchestrationService { get @@ -53,6 +70,9 @@ public IOrchestrationService OrchestrationService } } + /// + /// instance that can be used for constructing . + /// public IOrchestrationServiceClient OrchestrationServiceClient { get diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationProviderSettings.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderSettings.cs index ad5bd6203..2d959c557 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationProviderSettings.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderSettings.cs @@ -15,8 +15,16 @@ namespace DurableTask.ServiceFabric { using DurableTask.Settings; + /// + /// Provides settings for service fabric based custom provider implementations + /// for and + /// to be used in constructing and . + /// public sealed class FabricOrchestrationProviderSettings { + /// + /// Constructor. Initializes all settings to their default values. + /// public FabricOrchestrationProviderSettings() { TaskOrchestrationDispatcherSettings = new TaskOrchestrationDispatcherSettings() diff --git a/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs b/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs index a575d52e2..18c3bf2d2 100644 --- a/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs +++ b/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs @@ -19,7 +19,9 @@ namespace DurableTask.ServiceFabric using DurableTask.Tracking; using Microsoft.ServiceFabric.Data; - public interface IFabricOrchestrationServiceInstanceStore + // Todo: Figure out a way to not include internal XML documentation in the generated documentation file + // or change all the below comments to non-xml style. + internal interface IFabricOrchestrationServiceInstanceStore { /// /// Runs initialization to prepare the instance store for use diff --git a/src/DurableTask.ServiceFabric/Message.cs b/src/DurableTask.ServiceFabric/Message.cs index 788568d58..747a403f0 100644 --- a/src/DurableTask.ServiceFabric/Message.cs +++ b/src/DurableTask.ServiceFabric/Message.cs @@ -17,7 +17,7 @@ namespace DurableTask.ServiceFabric using System.Runtime.Serialization; [DataContract] - public class Message where TKey : IComparable, IEquatable + class Message where TKey : IComparable, IEquatable { public Message(TKey key, TValue value) { diff --git a/src/DurableTask.ServiceFabric/MessageProviderBase.cs b/src/DurableTask.ServiceFabric/MessageProviderBase.cs index 54ffd147e..80338962b 100644 --- a/src/DurableTask.ServiceFabric/MessageProviderBase.cs +++ b/src/DurableTask.ServiceFabric/MessageProviderBase.cs @@ -23,14 +23,14 @@ namespace DurableTask.ServiceFabric abstract class MessageProviderBase where TKey : IComparable, IEquatable { readonly string storeName; - readonly CancellationTokenSource cancellationTokenSource; readonly AsyncManualResetEvent waitEvent = new AsyncManualResetEvent(); + CancellationTokenSource cancellationTokenSource; + protected MessageProviderBase(IReliableStateManager stateManager, string storeName) { this.StateManager = stateManager; this.storeName = storeName; - this.cancellationTokenSource = new CancellationTokenSource(); } protected IReliableStateManager StateManager { get; } @@ -41,6 +41,7 @@ protected MessageProviderBase(IReliableStateManager stateManager, string storeNa public virtual async Task StartAsync() { + this.cancellationTokenSource = new CancellationTokenSource(); await InitializeStore(); using (var tx = this.StateManager.CreateTransaction()) @@ -166,7 +167,7 @@ protected void ThrowIfStopped() protected bool IsStopped() { - return this.cancellationTokenSource.IsCancellationRequested; + return this.cancellationTokenSource == null || this.cancellationTokenSource.IsCancellationRequested; } } } diff --git a/src/DurableTask.ServiceFabric/PersistentSession.api.cs b/src/DurableTask.ServiceFabric/PersistentSession.api.cs index 5c970f119..6e6c1ef70 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.api.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.api.cs @@ -19,7 +19,7 @@ namespace DurableTask.ServiceFabric using System.Linq; using DurableTask.History; - public sealed partial class PersistentSession + sealed partial class PersistentSession { public PersistentSession ReceiveMessages() { diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index e355780c8..359e52b21 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -19,7 +19,7 @@ namespace DurableTask.ServiceFabric using DurableTask.History; [DataContract] - public sealed partial class PersistentSession + sealed partial class PersistentSession { // Note : Ideally all the properties in this class should be readonly because this // class is designed to be immutable class. We use private settable properties @@ -70,7 +70,7 @@ public static PersistentSession Create(string sessionId, IImmutableList Date: Mon, 7 Nov 2016 18:05:22 -0800 Subject: [PATCH 124/210] Removing the nuproj files. --- .../DurableTask.ServiceFabric.nuproj | 43 ----------------- build/nuproj/DurableTask/DurableTask.nuproj | 47 ------------------- 2 files changed, 90 deletions(-) delete mode 100644 build/nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj delete mode 100644 build/nuproj/DurableTask/DurableTask.nuproj diff --git a/build/nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj b/build/nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj deleted file mode 100644 index e09723dcf..000000000 --- a/build/nuproj/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuproj +++ /dev/null @@ -1,43 +0,0 @@ - - - - - Debug - AnyCPU - - - Release - AnyCPU - - - - - - - - 33d8ee20-43d5-4d8e-8bec-36914ae49657 - - - $(MSBuildExtensionsPath)\NuProj\ - - - - DurableTask.ServiceFabric - 0.0.1-alpha - DurableTask.ServiceFabric - pradeek - pradeek - Service fabric based storage provider for Durable Task Framework. - Service fabric based storage provider for Durable Task Framework. - - - - - - - Copyright © 2016 - ServiceFabric Azure Task Durable Orchestration Workflow Activity Reliable - false - - - \ No newline at end of file diff --git a/build/nuproj/DurableTask/DurableTask.nuproj b/build/nuproj/DurableTask/DurableTask.nuproj deleted file mode 100644 index e698a0243..000000000 --- a/build/nuproj/DurableTask/DurableTask.nuproj +++ /dev/null @@ -1,47 +0,0 @@ - - - - - Debug - AnyCPU - - - Release - AnyCPU - - - - - - - 68e5007e-2e0a-4b74-be1e-56ca0e3d4e80 - - - $(MSBuildExtensionsPath)\NuProj\ - - - - DurableTask - 2.0.4-alpha - Durable Task Framework - affandar;siport - affandar;siport - Framework for writing code workflows in C#. - -Release notes for this release: -https://github.com/azure/durabletask/releases/tag/2.0.4-alpha - - This package provides a C# based durable Task framework for writing long running applications. - -It is built from an OSS version of https://www.nuget.org/packages/ServiceBus.DurableTask. - - - - https://github.com/azure/durabletask - https://github.com/azure/durabletask/blob/vnext/LICENSE - Copyright 2013 - en-US - ServiceBus Service Bus Azure Task Durable Orchestration Workflow Activity Reliable - - - \ No newline at end of file From eb394af0ef6193865cb41b1092275fb578b0949c Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Sat, 17 Dec 2016 06:09:02 -0800 Subject: [PATCH 125/210] Changes to support querying the state using only instance id without knowing execution id. Only latest execution id is supported. --- .../FunctionalTests.cs | 40 ++++++++++++++++++ .../TestApplication.Common/IRemoteClient.cs | 4 ++ .../TestStatefulService.cs | 17 ++++++-- src/DurableTask.ServiceFabric/Constants.cs | 1 + .../FabricOrchestrationInstanceStore.cs | 41 +++++++++++++++---- .../FabricOrchestrationServiceClient.cs | 16 +++++++- ...FabricOrchestrationServiceInstanceStore.cs | 2 +- 7 files changed, 105 insertions(+), 16 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs index 81d9aec35..0fe17f146 100644 --- a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs @@ -115,6 +115,46 @@ public async Task Orchestration_With_TimeoutWrapper_Test() Console.WriteLine($"Time for Orchestration with 5 second running task wrapped in 1 second timeout : {result.CompletedTime - result.CreatedTime}"); } + [TestMethod] + public async Task QueryState_For_Latest_Execution() + { + var instanceId = "PredicatbleInstanceId"; + var instance = await this.serviceClient.StartTestOrchestrationWithInstanceIdAsync(instanceId, new TestOrchestrationData() + { + NumberOfParallelTasks = 0, + NumberOfSerialTasks = 1, + MaxDelay = 15, + MinDelay = 15, + DelayUnit = TimeSpan.FromSeconds(1), + }); + + var state = await this.serviceClient.GetOrchestrationStateWithInstanceId(instanceId); + + Assert.IsNotNull(state); + Assert.AreEqual(instance.ExecutionId, state.OrchestrationInstance.ExecutionId); + + var result = await this.serviceClient.WaitForOrchestration(instance, TimeSpan.FromMinutes(2)); + Assert.AreEqual(OrchestrationStatus.Completed, result.OrchestrationStatus); + + var newInstance = await this.serviceClient.StartTestOrchestrationWithInstanceIdAsync(instanceId, new TestOrchestrationData() + { + NumberOfParallelTasks = 0, + NumberOfSerialTasks = 1, + MaxDelay = 0, + MinDelay = 0, + DelayUnit = TimeSpan.FromSeconds(1), + }); + + var newState = await this.serviceClient.GetOrchestrationStateWithInstanceId(instanceId); + + Assert.IsNotNull(newState); + Assert.AreEqual(newInstance.ExecutionId, newState.OrchestrationInstance.ExecutionId); + Assert.AreNotEqual(state.OrchestrationInstance.ExecutionId, newState.OrchestrationInstance.ExecutionId); + + result = await this.serviceClient.WaitForOrchestration(instance, TimeSpan.FromMinutes(2)); + Assert.AreEqual(OrchestrationStatus.Completed, result.OrchestrationStatus); + } + [TestMethod] public async Task Purge_Removes_State() { diff --git a/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs b/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs index 6f75f4fd8..c3909b97b 100644 --- a/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs +++ b/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs @@ -29,6 +29,10 @@ public interface IRemoteClient : IService Task GetOrchestrationState(OrchestrationInstance instance); + Task StartTestOrchestrationWithInstanceIdAsync(string instanceId, TestOrchestrationData input); + + Task GetOrchestrationStateWithInstanceId(string instanceId); + Task WaitForOrchestration(OrchestrationInstance instance, TimeSpan waitTimeout); Task PurgeOrchestrationHistoryEventsAsync(); diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index c3f1af775..ad0698060 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -100,11 +100,9 @@ public async Task RunDriverOrchestrationAsync(DriverOrchestr return await this.RunOrchestrationAsync(typeof(DriverOrchestration).Name, input, waitTimeout); } - public async Task StartTestOrchestrationAsync(TestOrchestrationData input) + public Task StartTestOrchestrationAsync(TestOrchestrationData input) { - var instance = await client.CreateOrchestrationInstanceAsync(typeof(TestOrchestration), input); - ServiceEventSource.Current.Message($"Orchestration Started : {instance.InstanceId}"); - return instance; + return client.CreateOrchestrationInstanceAsync(typeof(TestOrchestration), input); } public Task GetOrchestrationState(OrchestrationInstance instance) @@ -141,6 +139,17 @@ Type GetOrchestrationType(string typeName) return KnownOrchestrationTypeNames.First(kvp => string.Equals(typeName, kvp.Key)).Value; } + public Task StartTestOrchestrationWithInstanceIdAsync(string instanceId, TestOrchestrationData input) + { + return client.CreateOrchestrationInstanceAsync(typeof(TestOrchestration), instanceId, input); + } + + public async Task GetOrchestrationStateWithInstanceId(string instanceId) + { + var allStates = await this.client.GetOrchestrationStateAsync(instanceId, allExecutions: false); + return allStates.FirstOrDefault(); + } + static Dictionary KnownOrchestrationTypeNames = new Dictionary { { typeof(SimpleOrchestrationWithTasks).Name, typeof(SimpleOrchestrationWithTasks) }, diff --git a/src/DurableTask.ServiceFabric/Constants.cs b/src/DurableTask.ServiceFabric/Constants.cs index 37283c550..a07d291d9 100644 --- a/src/DurableTask.ServiceFabric/Constants.cs +++ b/src/DurableTask.ServiceFabric/Constants.cs @@ -18,6 +18,7 @@ static class Constants internal const string OrchestrationDictionaryName = "Orchestrations"; internal const string ActivitiesQueueName = "Activities"; internal const string InstanceStoreDictionaryName = "InstanceStore"; + internal const string ExecutionStoreDictionaryName = "ExecutionIdStore"; internal const string ScheduledMessagesDictionaryName = "ScheduledMessages"; } } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs index e43f39746..22d276b13 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs @@ -15,6 +15,7 @@ namespace DurableTask.ServiceFabric { using System; using System.Collections.Generic; + using System.Linq; using System.Threading; using System.Threading.Tasks; using DurableTask.Tracking; @@ -30,9 +31,11 @@ class FabricOrchestrationInstanceStore : IFabricOrchestrationServiceInstanceStor const string TimeFormatString = "yyyy-MM-dd-HH"; const string TimeFormatStringPrefix = "yyyy-MM-dd-"; readonly IReliableStateManager stateManager; + readonly List EmptyInstance = new List(); CancellationTokenSource cancellationTokenSource; IReliableDictionary instanceStore; + IReliableDictionary executionIdStore; public FabricOrchestrationInstanceStore(IReliableStateManager stateManager) { @@ -50,7 +53,8 @@ public async Task InitializeStoreAsync(bool recreate) public async Task StartAsync() { this.cancellationTokenSource = new CancellationTokenSource(); - this.instanceStore = await this.GetOrAddInstanceStoreDictionary(); + this.instanceStore = await this.stateManager.GetOrAddAsync>(Constants.InstanceStoreDictionaryName); + this.executionIdStore = await this.stateManager.GetOrAddAsync>(Constants.ExecutionStoreDictionaryName); var nowait = CleanupDayOldDictionaries(); } @@ -63,6 +67,7 @@ public Task StopAsync(bool isForced) public async Task DeleteStoreAsync() { await this.stateManager.RemoveAsync(Constants.InstanceStoreDictionaryName); + await this.stateManager.RemoveAsync(Constants.ExecutionStoreDictionaryName); } public async Task WriteEntitesAsync(ITransaction transaction, IEnumerable entities) @@ -73,10 +78,15 @@ public async Task WriteEntitesAsync(ITransaction transaction, IEnumerable instance.ExecutionId); + } await this.instanceStore.AddOrUpdateAsync(transaction, key, state.State, (k, oldValue) => state.State); } @@ -98,9 +108,27 @@ await backupDictionary.AddOrUpdateAsync(transaction, key, state.State, } } - public Task> GetOrchestrationStateAsync(string instanceId, bool allInstances) + public async Task> GetOrchestrationStateAsync(string instanceId, bool allInstances) { - throw new NotImplementedException(); + if (allInstances) + { + throw new NotImplementedException("Querying for state across all executions for an orchestration is not supported, only the latest execution can be queried"); + } + + using (var tx = this.stateManager.CreateTransaction()) + { + var executionIdValue = await this.executionIdStore.TryGetValueAsync(tx, instanceId); + if (executionIdValue.HasValue) + { + var state = await GetOrchestrationStateAsync(instanceId, executionIdValue.Value); + if (state != null) + { + return new List() { state }; + } + } + } + + return EmptyInstance; } public async Task GetOrchestrationStateAsync(string instanceId, string executionId) @@ -155,11 +183,6 @@ public Task PurgeOrchestrationHistoryEventsAsync(DateTime threshholdHourlyDateTi return this.stateManager.RemoveAsync(GetDictionaryKeyFromTime(threshholdHourlyDateTimeUtc)); } - Task> GetOrAddInstanceStoreDictionary() - { - return this.stateManager.GetOrAddAsync>(Constants.InstanceStoreDictionaryName); - } - string GetKey(string instanceId, string executionId) { return string.Concat(instanceId, "_", executionId); diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index 2476c28a1..eefbe5f72 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -76,9 +76,21 @@ public async Task ForceTerminateTaskOrchestrationAsync(string instanceId, string await SendTaskOrchestrationMessageAsync(taskMessage); } - public Task> GetOrchestrationStateAsync(string instanceId, bool allExecutions) + public async Task> GetOrchestrationStateAsync(string instanceId, bool allExecutions) { - throw new NotImplementedException(); + ThrowIfInstanceStoreNotConfigured(); + + var stateInstances = await this.instanceStore.GetOrchestrationStateAsync(instanceId, allExecutions); + + var result = new List(); + foreach(var stateInstance in stateInstances) + { + if (stateInstance != null) + { + result.Add(stateInstance.State); + } + } + return result; } public async Task GetOrchestrationStateAsync(string instanceId, string executionId) diff --git a/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs b/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs index 18c3bf2d2..7c180c77b 100644 --- a/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs +++ b/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs @@ -60,7 +60,7 @@ internal interface IFabricOrchestrationServiceInstanceStore /// The instance id to return state for /// Flag indiciation whether to get all history execution ids or just the most recent /// List of matching orchestration states - Task> GetOrchestrationStateAsync(string instanceId, bool allInstances); + Task> GetOrchestrationStateAsync(string instanceId, bool allInstances); /// /// Gets the orchestration state for a given instance and execution id From 53386ddb5b1b2a9c578b9f9104fc007e936ccfcb Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Tue, 3 Jan 2017 10:46:42 -0800 Subject: [PATCH 126/210] Handling code review comments for previous checkin. - Adding a test to make sure an orchestration with same id can't be started while another one is running. - Other minor code review comments. --- .../DurableTask.ServiceFabric.Test.csproj | 1 + .../FunctionalTests.cs | 23 +++++++++ .../Utilities.cs | 49 +++++++++++++++++++ .../FabricOrchestrationInstanceStore.cs | 5 +- 4 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 Test/DurableTask.ServiceFabric.Test/Utilities.cs diff --git a/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj b/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj index aa57b7dd8..7b84ed578 100644 --- a/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj +++ b/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj @@ -78,6 +78,7 @@ + diff --git a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs index 0fe17f146..1bccdba52 100644 --- a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs @@ -115,6 +115,28 @@ public async Task Orchestration_With_TimeoutWrapper_Test() Console.WriteLine($"Time for Orchestration with 5 second running task wrapped in 1 second timeout : {result.CompletedTime - result.CreatedTime}"); } + [TestMethod] + public async Task Orchestration_With_Same_Id_Cant_Be_Started_While_Running() + { + var instanceId = "PredicatbleInstanceId"; + var testData = new TestOrchestrationData() + { + NumberOfParallelTasks = 0, + NumberOfSerialTasks = 1, + MaxDelay = 15, + MinDelay = 15, + DelayUnit = TimeSpan.FromSeconds(1), + }; + + var instance = await this.serviceClient.StartTestOrchestrationWithInstanceIdAsync(instanceId, testData); + + await Utilities.ThrowsException(() => this.serviceClient.StartTestOrchestrationWithInstanceIdAsync(instanceId, testData), + $"An orchestration with id '{instanceId}' is already running."); + + var result = await this.serviceClient.WaitForOrchestration(instance, TimeSpan.FromMinutes(2)); + Assert.AreEqual(OrchestrationStatus.Completed, result.OrchestrationStatus); + } + [TestMethod] public async Task QueryState_For_Latest_Execution() { @@ -145,6 +167,7 @@ public async Task QueryState_For_Latest_Execution() DelayUnit = TimeSpan.FromSeconds(1), }); + // We want to make sure that once an orchestration is complete, we can create another instance with the same id. var newState = await this.serviceClient.GetOrchestrationStateWithInstanceId(instanceId); Assert.IsNotNull(newState); diff --git a/Test/DurableTask.ServiceFabric.Test/Utilities.cs b/Test/DurableTask.ServiceFabric.Test/Utilities.cs new file mode 100644 index 000000000..c4891105b --- /dev/null +++ b/Test/DurableTask.ServiceFabric.Test/Utilities.cs @@ -0,0 +1,49 @@ +// ---------------------------------------------------------------------------------- +// Copyright Microsoft Corporation +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ---------------------------------------------------------------------------------- + +using System; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DurableTask.ServiceFabric.Test +{ + public static class Utilities + { + public static async Task ThrowsException(Func action, string expectedMessage) where TException : Exception + { + try + { + await action(); + Assert.Fail($"Method {action.Method} did not throw the expected exception of type {typeof(TException).Name}"); + } + catch (Exception ex) + { + AggregateException aggregate = ex as AggregateException; + if (aggregate != null) + { + ex = aggregate.InnerException; + } + + TException expected = ex as TException; + if (expected == null) + { + Assert.Fail($"Method {action.Method} is expected to throw exception of type {typeof(TException).Name} but has thrown {ex.GetType().Name} instead."); + } + else if (!string.Equals(expected.Message, expectedMessage, StringComparison.Ordinal)) + { + Assert.Fail($"Method {action.Method} is expected to throw exception with message '{expectedMessage}' but has thrown the message '{expected.Message}' instead."); + } + } + } + } +} diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs index 22d276b13..eb42b3bbf 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs @@ -15,7 +15,7 @@ namespace DurableTask.ServiceFabric { using System; using System.Collections.Generic; - using System.Linq; + using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using DurableTask.Tracking; @@ -31,7 +31,6 @@ class FabricOrchestrationInstanceStore : IFabricOrchestrationServiceInstanceStor const string TimeFormatString = "yyyy-MM-dd-HH"; const string TimeFormatStringPrefix = "yyyy-MM-dd-"; readonly IReliableStateManager stateManager; - readonly List EmptyInstance = new List(); CancellationTokenSource cancellationTokenSource; IReliableDictionary instanceStore; @@ -128,7 +127,7 @@ public async Task> GetOrchestrationState } } - return EmptyInstance; + return ImmutableList.Empty; } public async Task GetOrchestrationStateAsync(string instanceId, string executionId) From 22257064fcfa8b1c327d30dbf72bbf3ef39662e8 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Wed, 4 Jan 2017 14:45:13 -0800 Subject: [PATCH 127/210] Generated and uploaded the 'alpha2' version of respective packages, bumping the version in nuspec for future generation. --- src/DurableTask.Framework/DurableTask.Framework.nuspec | 2 +- src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DurableTask.Framework/DurableTask.Framework.nuspec b/src/DurableTask.Framework/DurableTask.Framework.nuspec index 81e9255fa..bfba76040 100644 --- a/src/DurableTask.Framework/DurableTask.Framework.nuspec +++ b/src/DurableTask.Framework/DurableTask.Framework.nuspec @@ -2,7 +2,7 @@ DurableTask - 2.0.4-alpha2 + 2.0.4-alpha3 Durable Task Framework affandar;siport affandar;siport diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec index ebb96960d..5e751c7fc 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec @@ -2,7 +2,7 @@ DurableTask.ServiceFabric - 0.0.1-alpha2 + 0.0.1-alpha3 DurableTask.ServiceFabric pradeek pradeek From 8698d7e42b4761b3f0a398fe119629b11b76ff49 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Wed, 4 Jan 2017 15:17:21 -0800 Subject: [PATCH 128/210] Updating the version of dll to match the version of nuget package that is being generated from this branch. --- src/DurableTask.Framework/Properties/AssemblyInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DurableTask.Framework/Properties/AssemblyInfo.cs b/src/DurableTask.Framework/Properties/AssemblyInfo.cs index cb3f577e8..d6ae37665 100644 --- a/src/DurableTask.Framework/Properties/AssemblyInfo.cs +++ b/src/DurableTask.Framework/Properties/AssemblyInfo.cs @@ -24,8 +24,8 @@ [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("1d626d8b-330b-4c6a-b689-c0fefbeb99cd")] -[assembly: AssemblyVersion("1.0.0.6")] -[assembly: AssemblyFileVersion("1.0.0.6")] +[assembly: AssemblyVersion("2.0.4.0")] +[assembly: AssemblyFileVersion("2.0.4.0")] [assembly: InternalsVisibleTo("DurableTask.Framework.Tests")] [assembly: InternalsVisibleTo("DurableTask.ServiceBus.Tests")] From f29a663c1404dcca4afb8e2dfa04a67ee8b17490 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Wed, 4 Jan 2017 15:27:41 -0800 Subject: [PATCH 129/210] Generated and uploaded the 'alpha3' version of respective packages, bumping the version in nuspec for future generation. (Had to immediately do this because there were some issues / missed steps with generating alpha2 package, ex : signing) --- src/DurableTask.Framework/DurableTask.Framework.nuspec | 2 +- src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DurableTask.Framework/DurableTask.Framework.nuspec b/src/DurableTask.Framework/DurableTask.Framework.nuspec index bfba76040..67051f90a 100644 --- a/src/DurableTask.Framework/DurableTask.Framework.nuspec +++ b/src/DurableTask.Framework/DurableTask.Framework.nuspec @@ -2,7 +2,7 @@ DurableTask - 2.0.4-alpha3 + 2.0.4-alpha4 Durable Task Framework affandar;siport affandar;siport diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec index 5e751c7fc..cb2a98b72 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec @@ -2,7 +2,7 @@ DurableTask.ServiceFabric - 0.0.1-alpha3 + 0.0.1-alpha4 DurableTask.ServiceFabric pradeek pradeek From 0813bb5d68b90f8655b1feb3dfa7ed773410cf67 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Mon, 30 Jan 2017 13:45:55 -0800 Subject: [PATCH 130/210] Fixing a potential null ref. --- src/DurableTask.ServiceFabric/MessageProviderBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DurableTask.ServiceFabric/MessageProviderBase.cs b/src/DurableTask.ServiceFabric/MessageProviderBase.cs index 80338962b..b9826a640 100644 --- a/src/DurableTask.ServiceFabric/MessageProviderBase.cs +++ b/src/DurableTask.ServiceFabric/MessageProviderBase.cs @@ -31,6 +31,7 @@ protected MessageProviderBase(IReliableStateManager stateManager, string storeNa { this.StateManager = stateManager; this.storeName = storeName; + this.cancellationTokenSource = new CancellationTokenSource(); } protected IReliableStateManager StateManager { get; } @@ -41,7 +42,6 @@ protected MessageProviderBase(IReliableStateManager stateManager, string storeNa public virtual async Task StartAsync() { - this.cancellationTokenSource = new CancellationTokenSource(); await InitializeStore(); using (var tx = this.StateManager.CreateTransaction()) @@ -167,7 +167,7 @@ protected void ThrowIfStopped() protected bool IsStopped() { - return this.cancellationTokenSource == null || this.cancellationTokenSource.IsCancellationRequested; + return this.cancellationTokenSource.IsCancellationRequested; } } } From ed9b55f416e6f141df08050f76991c67405e78b6 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Mon, 30 Jan 2017 13:47:13 -0800 Subject: [PATCH 131/210] Minor optimization. --- .../FabricOrchestrationProviderFactory.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs index 82c4a8bfe..e73781242 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderFactory.cs @@ -54,7 +54,7 @@ public FabricOrchestrationProviderFactory(IReliableStateManager stateManager, Fa } this.stateManager = stateManager; - @lock = new object(); + this.@lock = new object(); this.settings = settings ?? new FabricOrchestrationProviderSettings(); } @@ -84,14 +84,17 @@ public IOrchestrationServiceClient OrchestrationServiceClient void Initialize() { - lock (@lock) + if (this.orchestrationService == null) { - if (this.orchestrationService == null) + lock (this.@lock) { - this.sessionsProvider = new SessionsProvider(this.stateManager); - this.instanceStore = new FabricOrchestrationInstanceStore(this.stateManager); - this.orchestrationService = new FabricOrchestrationService(this.stateManager, this.sessionsProvider, this.instanceStore, this.settings); - this.orchestrationClient = new FabricOrchestrationServiceClient(this.stateManager, this.sessionsProvider, this.instanceStore); + if (this.orchestrationService == null) + { + this.sessionsProvider = new SessionsProvider(this.stateManager); + this.instanceStore = new FabricOrchestrationInstanceStore(this.stateManager); + this.orchestrationService = new FabricOrchestrationService(this.stateManager, this.sessionsProvider, this.instanceStore, this.settings); + this.orchestrationClient = new FabricOrchestrationServiceClient(this.stateManager, this.sessionsProvider, this.instanceStore); + } } } } From 4dcc522eda7e76f08ee34dd3cad3f016991c33ca Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Thu, 2 Feb 2017 11:49:01 -0800 Subject: [PATCH 132/210] Fixing release build break. --- src/DurableTask.ServiceFabric/MessageProviderBase.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/DurableTask.ServiceFabric/MessageProviderBase.cs b/src/DurableTask.ServiceFabric/MessageProviderBase.cs index b9826a640..e9fb4521d 100644 --- a/src/DurableTask.ServiceFabric/MessageProviderBase.cs +++ b/src/DurableTask.ServiceFabric/MessageProviderBase.cs @@ -15,11 +15,13 @@ namespace DurableTask.ServiceFabric { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; + [SuppressMessage("Microsoft.Design", "CA1001", Justification = "Disposing is done through StartAsync and StopAsync")] abstract class MessageProviderBase where TKey : IComparable, IEquatable { readonly string storeName; @@ -70,6 +72,7 @@ protected async Task InitializeStore() public Task StopAsync() { this.cancellationTokenSource.Cancel(); + this.cancellationTokenSource.Dispose(); return Task.FromResult(null); } From 62e417f4e34616bdc956d42c41154c694c3c6842 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Thu, 2 Feb 2017 12:09:05 -0800 Subject: [PATCH 133/210] Generated and uploaded the 'alpha4' version of respective packages, changing the version in nuspec for future generation. --- src/DurableTask.Framework/DurableTask.Framework.nuspec | 2 +- src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DurableTask.Framework/DurableTask.Framework.nuspec b/src/DurableTask.Framework/DurableTask.Framework.nuspec index 67051f90a..2da453f4a 100644 --- a/src/DurableTask.Framework/DurableTask.Framework.nuspec +++ b/src/DurableTask.Framework/DurableTask.Framework.nuspec @@ -2,7 +2,7 @@ DurableTask - 2.0.4-alpha4 + 2.0.4-beta1 Durable Task Framework affandar;siport affandar;siport diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec index cb2a98b72..9c634bd34 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.nuspec @@ -2,7 +2,7 @@ DurableTask.ServiceFabric - 0.0.1-alpha4 + 0.0.1-beta1 DurableTask.ServiceFabric pradeek pradeek From 28547d2222591c8181ee0c0fc6a57786c3ca5b42 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Tue, 7 Feb 2017 19:46:52 -0800 Subject: [PATCH 134/210] Add ETW event for current pending entry count for all stores in DTFX. --- .../MessageProviderBase.cs | 19 +++++++++++++++++++ .../ProviderEventSource.cs | 10 ++++++++++ .../ScheduledMessageProvider.cs | 1 + 3 files changed, 30 insertions(+) diff --git a/src/DurableTask.ServiceFabric/MessageProviderBase.cs b/src/DurableTask.ServiceFabric/MessageProviderBase.cs index e9fb4521d..a2c90af5d 100644 --- a/src/DurableTask.ServiceFabric/MessageProviderBase.cs +++ b/src/DurableTask.ServiceFabric/MessageProviderBase.cs @@ -26,6 +26,7 @@ abstract class MessageProviderBase where TKey : IComparable, { readonly string storeName; readonly AsyncManualResetEvent waitEvent = new AsyncManualResetEvent(); + readonly TimeSpan metricsInterval = TimeSpan.FromMinutes(5); CancellationTokenSource cancellationTokenSource; @@ -62,6 +63,8 @@ public virtual async Task StartAsync() } } } + + var nowait = LogMetrics(); } protected async Task InitializeStore() @@ -172,5 +175,21 @@ protected bool IsStopped() { return this.cancellationTokenSource.IsCancellationRequested; } + + protected async Task LogMetrics() + { + while (!IsStopped()) + { + await Task.Delay(metricsInterval, this.CancellationToken); + + long count = 0; + using (var tx = this.StateManager.CreateTransaction()) + { + count = await this.Store.GetCountAsync(tx); + } + + ProviderEventSource.Instance.LogStoreCount(this.storeName, count); + } + } } } diff --git a/src/DurableTask.ServiceFabric/ProviderEventSource.cs b/src/DurableTask.ServiceFabric/ProviderEventSource.cs index b3651bf3b..ddad7f537 100644 --- a/src/DurableTask.ServiceFabric/ProviderEventSource.cs +++ b/src/DurableTask.ServiceFabric/ProviderEventSource.cs @@ -36,6 +36,7 @@ public static class Keywords { public const EventKeywords Orchestration = (EventKeywords) 0x1L; public const EventKeywords Activity = (EventKeywords) 0x2L; + public const EventKeywords Common = (EventKeywords)0x4L; } [Event(1, Level = EventLevel.Informational, Message = "Orchestration {0} Created.")] @@ -64,5 +65,14 @@ public void LogException(string message, string stackTrace) WriteEvent(3, message, stackTrace); } } + + [Event(4, Level = EventLevel.Informational, Message = "Current number of entries in store {0} : {1}")] + public void LogStoreCount(string storeName, long count) + { + if (IsEnabled(EventLevel.Informational, Keywords.Common)) + { + WriteEvent(4, storeName, count); + } + } } } diff --git a/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs b/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs index 003c9d052..b96638f73 100644 --- a/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs +++ b/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs @@ -60,6 +60,7 @@ public override async Task StartAsync() } } + var metricsTask = LogMetrics(); var nowait = ProcessScheduledMessages(); } From ff7a0904873e0cbf6c7bf528aa4d4993df5ee584 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Thu, 9 Feb 2017 22:06:27 -0800 Subject: [PATCH 135/210] forcing the termination of Task hub worker to see how that works and to match what would be most use case. --- .../TestStatefulService/TestStatefulService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index ad0698060..9a5cf157b 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -84,7 +84,7 @@ protected override async Task OnChangeRoleAsync(ReplicaRole newRole, Cancellatio if (newRole != ReplicaRole.Primary && this.currentRole == ReplicaRole.Primary) { //await this.testExecutor.StopAsync(); - await this.worker.StopAsync(); + await this.worker.StopAsync(isForced: true); } this.currentRole = newRole; } From 7d32cf75c50308dbf1f4d076a6b7f0b39533dac2 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Fri, 10 Feb 2017 16:10:13 -0800 Subject: [PATCH 136/210] Fixing a potential race. Though I couldn't repro the issue locally, I think this is causing some random issue we are seeing in stress. (StartAsync throwing an exception saying unable to compare items in array) --- .../Perf/TestOrchestration.cs | 19 +++++++++++-------- .../TestStatefulService.cs | 11 +---------- .../ProviderEventSource.cs | 9 +++++++++ .../ScheduledMessageProvider.cs | 15 +++++++++++++-- 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs index 560f62ffa..72d8b636b 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs @@ -43,13 +43,16 @@ async Task RunTaskCore(OrchestrationContext context, TestOrchestrationData int j = 0; for (; i < data.NumberOfParallelTasks; i++) { - results.Add(context.ScheduleTask(typeof(RandomTimeWaitingTask), new RandomTimeWaitingTaskInput - { - TaskId = "ParallelTask: " + i.ToString(), - MaxDelay = data.MaxDelay, - MinDelay = data.MinDelay, - DelayUnit = data.DelayUnit - })); + results.Add(context.ScheduleWithRetry( + typeof(RandomTimeWaitingTask), + new RetryOptions(TimeSpan.FromSeconds(5), 5), + new RandomTimeWaitingTaskInput + { + TaskId = "ParallelTask: " + i.ToString(), + MaxDelay = data.MaxDelay, + MinDelay = data.MinDelay, + DelayUnit = data.DelayUnit + })); } int[] counters = await Task.WhenAll(results.ToArray()); @@ -59,7 +62,7 @@ async Task RunTaskCore(OrchestrationContext context, TestOrchestrationData { int c = await context.ScheduleTask(typeof(RandomTimeWaitingTask), new RandomTimeWaitingTaskInput { - TaskId = "SerialTask" + (i + j).ToString(), + TaskId = "SerialTask" + (i + j), MaxDelay = data.MaxDelay, MinDelay = data.MinDelay, DelayUnit = data.DelayUnit diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index 9a5cf157b..fbef53b15 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -112,16 +112,7 @@ public Task GetOrchestrationState(OrchestrationInstance inst public async Task WaitForOrchestration(OrchestrationInstance instance, TimeSpan waitTimeout) { - var state = await client.WaitForOrchestrationAsync(instance, waitTimeout); - if (state == null) - { - ServiceEventSource.Current.Message($"Orchestration {instance.InstanceId} perhaps timed out while waiting."); - } - else - { - ServiceEventSource.Current.Message($"Orchestration {instance.InstanceId} finished with status : {state.OrchestrationStatus}, result : {state.Output}, created time : {state.CreatedTime}, completed time : {state.CompletedTime}."); - } - return state; + return await client.WaitForOrchestrationAsync(instance, waitTimeout); } public Task PurgeOrchestrationHistoryEventsAsync() diff --git a/src/DurableTask.ServiceFabric/ProviderEventSource.cs b/src/DurableTask.ServiceFabric/ProviderEventSource.cs index ddad7f537..c1bce2933 100644 --- a/src/DurableTask.ServiceFabric/ProviderEventSource.cs +++ b/src/DurableTask.ServiceFabric/ProviderEventSource.cs @@ -74,5 +74,14 @@ public void LogStoreCount(string storeName, long count) WriteEvent(4, storeName, count); } } + + [Event(5, Level = EventLevel.Error, Message = "We are seeing something that we don't expect to see : {0}")] + public void LogUnexpectedCodeCondition(string uniqueMessage) + { + if (IsEnabled(EventLevel.Informational, Keywords.Orchestration)) + { + WriteEvent(5, uniqueMessage); + } + } } } diff --git a/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs b/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs index b96638f73..663b77de3 100644 --- a/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs +++ b/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs @@ -52,11 +52,22 @@ public override async Task StartAsync() { while (await enumerator.MoveNextAsync(this.CancellationToken)) { - builder.Add(new Message(enumerator.Current.Key, enumerator.Current.Value)); + var timerEvent = enumerator.Current.Value?.Event as TimerFiredEvent; + if (timerEvent == null) + { + ProviderEventSource.Instance.LogUnexpectedCodeCondition($"{nameof(ScheduledMessageProvider)}.{nameof(StartAsync)} : Seeing a non timer event in scheduled messages while filling the pending items collection in role start"); + } + else + { + builder.Add(new Message(enumerator.Current.Key, enumerator.Current.Value)); + } } } - this.inMemorySet = builder.ToImmutableSortedSet(); + lock (@lock) + { + this.inMemorySet = builder.ToImmutableSortedSet(); + } } } From d07834cd26af051af404df778d553db78bf66ff2 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Fri, 10 Feb 2017 16:22:36 -0800 Subject: [PATCH 137/210] Fixing a minor thing that I missed in my last check in. --- src/DurableTask.ServiceFabric/ProviderEventSource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DurableTask.ServiceFabric/ProviderEventSource.cs b/src/DurableTask.ServiceFabric/ProviderEventSource.cs index c1bce2933..9331733b8 100644 --- a/src/DurableTask.ServiceFabric/ProviderEventSource.cs +++ b/src/DurableTask.ServiceFabric/ProviderEventSource.cs @@ -78,7 +78,7 @@ public void LogStoreCount(string storeName, long count) [Event(5, Level = EventLevel.Error, Message = "We are seeing something that we don't expect to see : {0}")] public void LogUnexpectedCodeCondition(string uniqueMessage) { - if (IsEnabled(EventLevel.Informational, Keywords.Orchestration)) + if (IsEnabled(EventLevel.Error, Keywords.Common)) { WriteEvent(5, uniqueMessage); } From 19f01fd5d21f92f4b7d468d9de2f3282447e2598 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Wed, 22 Feb 2017 21:40:33 -0800 Subject: [PATCH 138/210] A couple of fixes: - Using the MDT.EventSource Nuget package for EventSource to get channels support and renaming/rearranging some events/properties - Changing the default setting values for fabric provider settings --- .../DurableTask.ServiceFabric.csproj | 13 ++++++++++ .../DurableTask.ServiceFabric.nuspec | 8 +++--- .../FabricOrchestrationProviderSettings.cs | 6 ++--- .../FabricOrchestrationService.cs | 6 ++--- .../FabricOrchestrationServiceClient.cs | 2 +- .../MessageProviderBase.cs | 2 +- .../ProviderEventSource.cs | 26 +++++++++---------- .../ScheduledMessageProvider.cs | 2 +- src/DurableTask.ServiceFabric/packages.config | 3 +++ 9 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj index 691207135..fc19a0cf6 100644 --- a/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj +++ b/src/DurableTask.ServiceFabric/DurableTask.ServiceFabric.csproj @@ -12,6 +12,8 @@ DurableTask.ServiceFabric ..\..\ 512 + + true @@ -33,6 +35,10 @@ $(OutputPath)$(AssemblyName).xml + + $(SolutionDir)\packages\Microsoft.Diagnostics.Tracing.EventSource.Redist.1.1.28\lib\net40\Microsoft.Diagnostics.Tracing.EventSource.dll + True + $(SolutionDir)\packages\Microsoft.ServiceFabric.Data.2.1.163\lib\net45\Microsoft.ServiceFabric.Data.dll True @@ -119,6 +125,13 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + \ No newline at end of file diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs index 3bcd9d36a..00db5c27d 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs @@ -20,7 +20,8 @@ namespace DurableTask.ServiceFabric using System.Globalization; using System.Threading; using System.Threading.Tasks; - using DurableTask.Tracking; + using DurableTask.Core; + using DurableTask.Core.Tracking; using Microsoft.ServiceFabric.Data; using Microsoft.ServiceFabric.Data.Collections; diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationProvider.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationProvider.cs index c1a32f899..755c3c630 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationProvider.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationProvider.cs @@ -15,16 +15,17 @@ namespace DurableTask.ServiceFabric { using System; using System.Threading; + using DurableTask.Core; using Microsoft.ServiceFabric.Data; /// /// Manages instances of a service fabric based store provider implementations - /// for and - /// to be used in constructing and . + /// for and + /// to be used in constructing and . /// /// /// Use to create an instance of . - /// Note that this provider object should not be used once method is called + /// Note that this provider object should not be used once method is called /// on the worker object created using this provider. A new provider object should be created after that point. /// public sealed class FabricOrchestrationProvider : IDisposable @@ -45,7 +46,7 @@ internal FabricOrchestrationProvider(IReliableStateManager stateManager, FabricO } /// - /// instance that can be used for constructing . + /// instance that can be used for constructing . /// public IOrchestrationService OrchestrationService { @@ -57,7 +58,7 @@ public IOrchestrationService OrchestrationService } /// - /// instance that can be used for constructing . + /// instance that can be used for constructing . /// public IOrchestrationServiceClient OrchestrationServiceClient { @@ -81,8 +82,8 @@ public IFabricProviderClient FabricProviderClient } /// - /// Disposes the object. The object should be disposed after - /// is invoked on the created with the . + /// Disposes the object. The object should be disposed after + /// is invoked on the created with the . /// public void Dispose() { diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationProviderSettings.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderSettings.cs index 39b4c2462..c2b87677d 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationProviderSettings.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationProviderSettings.cs @@ -13,12 +13,13 @@ namespace DurableTask.ServiceFabric { - using DurableTask.Settings; + using DurableTask.Core; + using DurableTask.Core.Settings; /// /// Provides settings for service fabric based custom provider implementations - /// for and - /// to be used in constructing and . + /// for and + /// to be used in constructing and . /// public sealed class FabricOrchestrationProviderSettings { diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index fbd781ad5..a4e8c1dbf 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -20,8 +20,9 @@ namespace DurableTask.ServiceFabric using System.Linq; using System.Threading; using System.Threading.Tasks; - using DurableTask.History; - using DurableTask.Tracking; + using DurableTask.Core; + using DurableTask.Core.History; + using DurableTask.Core.Tracking; using Microsoft.ServiceFabric.Data; class FabricOrchestrationService : IOrchestrationService diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index dc2dc23ba..726a4e6d8 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -17,8 +17,9 @@ namespace DurableTask.ServiceFabric using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; - using DurableTask.History; - using DurableTask.Tracking; + using DurableTask.Core; + using DurableTask.Core.History; + using DurableTask.Core.Tracking; using Microsoft.ServiceFabric.Data; class FabricOrchestrationServiceClient : IOrchestrationServiceClient @@ -72,6 +73,11 @@ public async Task CreateTaskOrchestrationAsync(TaskMessage creationMessage) } } + public Task CreateTaskOrchestrationAsync(TaskMessage creationMessage, OrchestrationStatus[] dedupeStatuses) + { + throw new NotImplementedException(); + } + public Task SendTaskOrchestrationMessageAsync(TaskMessage message) { return this.orchestrationProvider.AppendMessageAsync(new TaskMessageItem(message)); diff --git a/src/DurableTask.ServiceFabric/FabricProviderClient.cs b/src/DurableTask.ServiceFabric/FabricProviderClient.cs index 26be87b28..f3f2e7cab 100644 --- a/src/DurableTask.ServiceFabric/FabricProviderClient.cs +++ b/src/DurableTask.ServiceFabric/FabricProviderClient.cs @@ -17,7 +17,8 @@ namespace DurableTask.ServiceFabric using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; - using DurableTask.Serializing; + using DurableTask.Core; + using DurableTask.Core.Serializing; using Microsoft.ServiceFabric.Data; using Newtonsoft.Json; diff --git a/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs b/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs index 05137f24b..75d01e1c7 100644 --- a/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs +++ b/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs @@ -15,9 +15,9 @@ namespace DurableTask.ServiceFabric { using System; using System.Collections.Generic; - using System.Threading; using System.Threading.Tasks; - using DurableTask.Tracking; + using DurableTask.Core; + using DurableTask.Core.Tracking; using Microsoft.ServiceFabric.Data; // Todo: Figure out a way to not include internal XML documentation in the generated documentation file diff --git a/src/DurableTask.ServiceFabric/IFabricProviderClient.cs b/src/DurableTask.ServiceFabric/IFabricProviderClient.cs index 9b9bf8821..b19b389de 100644 --- a/src/DurableTask.ServiceFabric/IFabricProviderClient.cs +++ b/src/DurableTask.ServiceFabric/IFabricProviderClient.cs @@ -16,9 +16,10 @@ namespace DurableTask.ServiceFabric using System; using System.Collections.Generic; using System.Threading.Tasks; + using DurableTask.Core; /// - /// Provides additional useful functionality which is not available through . + /// Provides additional useful functionality which is not available through . /// public interface IFabricProviderClient { @@ -31,7 +32,7 @@ public interface IFabricProviderClient /// /// Gets runtime state of a running or pending orchestration which includes the history events. /// - /// The + /// The /// of the orchestration. /// Returns serialized runtime state which includes all the history events if the /// orchestration is running or pending. diff --git a/src/DurableTask.ServiceFabric/OrchestrationInstanceComparer.cs b/src/DurableTask.ServiceFabric/OrchestrationInstanceComparer.cs index 6b2432547..e83fe4dc8 100644 --- a/src/DurableTask.ServiceFabric/OrchestrationInstanceComparer.cs +++ b/src/DurableTask.ServiceFabric/OrchestrationInstanceComparer.cs @@ -14,6 +14,7 @@ namespace DurableTask.ServiceFabric { using System.Collections.Generic; + using DurableTask.Core; internal class OrchestrationInstanceComparer : IEqualityComparer { diff --git a/src/DurableTask.ServiceFabric/OrchestrationStatusExtensions.cs b/src/DurableTask.ServiceFabric/OrchestrationStatusExtensions.cs index 9cdae9a4b..731557ad8 100644 --- a/src/DurableTask.ServiceFabric/OrchestrationStatusExtensions.cs +++ b/src/DurableTask.ServiceFabric/OrchestrationStatusExtensions.cs @@ -13,6 +13,8 @@ namespace DurableTask.ServiceFabric { + using DurableTask.Core; + static class OrchestrationStatusExtensions { public static bool IsTerminalState(this OrchestrationStatus status) diff --git a/src/DurableTask.ServiceFabric/PersistentSession.cs b/src/DurableTask.ServiceFabric/PersistentSession.cs index b80eb27d1..2acea3db9 100644 --- a/src/DurableTask.ServiceFabric/PersistentSession.cs +++ b/src/DurableTask.ServiceFabric/PersistentSession.cs @@ -16,7 +16,8 @@ namespace DurableTask.ServiceFabric using System.Collections.Generic; using System.Collections.Immutable; using System.Runtime.Serialization; - using DurableTask.History; + using DurableTask.Core; + using DurableTask.Core.History; [DataContract] sealed partial class PersistentSession : IExtensibleDataObject diff --git a/src/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs b/src/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs index c43c20d32..c91191876 100644 --- a/src/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs +++ b/src/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs @@ -1,38 +1,3 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("DurableTask.ServiceFabric")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("DurableTask.ServiceFabric")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("5c617b24-4902-4992-8f71-ab14f00b74a8")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("DurableTask.ServiceFabric.UnitTests")] diff --git a/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs b/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs index b3da612ce..eadc36ea6 100644 --- a/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs +++ b/src/DurableTask.ServiceFabric/ScheduledMessageProvider.cs @@ -19,9 +19,9 @@ namespace DurableTask.ServiceFabric using System.Linq; using System.Threading; using System.Threading.Tasks; - using DurableTask.History; + using DurableTask.Core; + using DurableTask.Core.History; using Microsoft.ServiceFabric.Data; - using Microsoft.ServiceFabric.Data.Collections; class ScheduledMessageProvider : MessageProviderBase { diff --git a/src/DurableTask.ServiceFabric/SessionsProvider.cs b/src/DurableTask.ServiceFabric/SessionsProvider.cs index 8028483fb..8894576b5 100644 --- a/src/DurableTask.ServiceFabric/SessionsProvider.cs +++ b/src/DurableTask.ServiceFabric/SessionsProvider.cs @@ -20,6 +20,7 @@ namespace DurableTask.ServiceFabric using System.Linq; using System.Threading; using System.Threading.Tasks; + using DurableTask.Core; using Microsoft.ServiceFabric.Data; /// diff --git a/src/DurableTask.ServiceFabric/TaskMessageItem.cs b/src/DurableTask.ServiceFabric/TaskMessageItem.cs index 55ff3d129..94d19fa15 100644 --- a/src/DurableTask.ServiceFabric/TaskMessageItem.cs +++ b/src/DurableTask.ServiceFabric/TaskMessageItem.cs @@ -15,6 +15,7 @@ namespace DurableTask.ServiceFabric { using System; using System.Runtime.Serialization; + using DurableTask.Core; [DataContract] sealed class TaskMessageItem : IExtensibleDataObject diff --git a/src/DurableTask.ServiceFabric/TimerFiredEventComparer.cs b/src/DurableTask.ServiceFabric/TimerFiredEventComparer.cs index 008f5ce89..0679aa7a9 100644 --- a/src/DurableTask.ServiceFabric/TimerFiredEventComparer.cs +++ b/src/DurableTask.ServiceFabric/TimerFiredEventComparer.cs @@ -15,7 +15,7 @@ namespace DurableTask.ServiceFabric { using System; using System.Collections.Generic; - using DurableTask.History; + using DurableTask.Core.History; sealed class TimerFiredEventComparer : IComparer> { diff --git a/src/DurableTask.ServiceFabric/Utils.cs b/src/DurableTask.ServiceFabric/Utils.cs index 563db1eed..b5adbfbfa 100644 --- a/src/DurableTask.ServiceFabric/Utils.cs +++ b/src/DurableTask.ServiceFabric/Utils.cs @@ -17,6 +17,7 @@ namespace DurableTask.ServiceFabric using System.Diagnostics; using System.Threading; using System.Threading.Tasks; + using DurableTask.Core; internal static class Utils { From baa4b658c2fdc58c5d282d1c787bf5983408f71b Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Thu, 23 Aug 2018 16:20:39 -0700 Subject: [PATCH 204/210] Changes to make the entire solution build. --- DurableTask.ServiceFabric.sln | 33 ------------------- ...leTask.ServiceFabric.Failover.Tests.csproj | 8 +++++ .../OrchestrationRunner.cs | 1 + .../app.config | 8 ++--- .../DurableTask.ServiceFabric.Test.csproj | 8 +++++ .../FunctionalTests.cs | 1 + .../StressTests.cs | 1 + .../WaitForOrchestrationTests.cs | 1 + .../DurableTask.ServiceFabric.Test/app.config | 16 ++++----- ...bleTask.ServiceFabric.Tests.Tooling.csproj | 8 ++++- .../Program.cs | 1 + .../app.config | 3 ++ ...DurableTask.ServiceFabric.UnitTests.csproj | 16 +++++++-- .../OrchestrationInstanceComparerTests.cs | 1 + .../PersistentSessionTests.cs | 6 ++-- .../TaskMessageItemTests.cs | 3 +- .../TimerFiredEventComparerTests.cs | 3 +- .../app.config | 12 +++---- .../packages.config | 2 +- .../Perf/ExecutionCountingActivity.cs | 1 + .../Perf/ExecutionCountingOrchestration.cs | 1 + .../Perf/RandomTimeWaitingTask.cs | 1 + .../Perf/TestOrchestration.cs | 2 +- .../TestApplication.Common/IRemoteClient.cs | 2 +- .../TestApplication.Common.csproj | 4 +++ .../ExceptionThrowingTask.cs | 2 +- .../GenerationBasicOrchestration.cs | 2 +- .../TestOrchestrations/GetUserTask.cs | 2 +- .../TestOrchestrations/GreetUserTask.cs | 2 +- .../OrchestrationRunningIntoRetry.cs | 5 ++- ...SimpleOrchestrationWithSubOrchestration.cs | 2 +- .../SimpleOrchestrationWithTasks.cs | 2 +- .../SimpleOrchestrationWithTimer.cs | 2 +- .../TestStatefulService.cs | 2 +- .../TestStatefulService.csproj | 4 +++ 35 files changed, 93 insertions(+), 75 deletions(-) create mode 100644 Test/DurableTask.ServiceFabric.Tests.Tooling/app.config diff --git a/DurableTask.ServiceFabric.sln b/DurableTask.ServiceFabric.sln index 3ea4ab0e9..b4c1c08c0 100644 --- a/DurableTask.ServiceFabric.sln +++ b/DurableTask.ServiceFabric.sln @@ -26,12 +26,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.ServiceFabric", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.ServiceFabric.Test", "Test\DurableTask.ServiceFabric.Test\DurableTask.ServiceFabric.Test.csproj", "{EDC63DDB-8397-4AEC-BF54-6395B2527075}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.Stress.Tests", "Test\DurableTask.Stress.Tests\DurableTask.Stress.Tests.csproj", "{96980359-8003-4500-B97B-949A7FE01F31}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DurableTask.ServiceBus.Tests", "Test\DurableTask.ServiceBus.Tests\DurableTask.ServiceBus.Tests.csproj", "{6639DA74-9063-4A7C-9484-0A71C4FB5C18}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.Framework.Tests", "Test\DurableTask.Framework.Tests\DurableTask.Framework.Tests.csproj", "{879670A7-919B-4AF9-8AFB-7C4EDAA0CC04}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DurableTask.Test.Orchestrations", "Test\DurableTask.Test.Orchestrations\DurableTask.Test.Orchestrations.csproj", "{2BC2A5AD-4200-41B9-A034-332BB1D7187B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DurableTask.ServiceFabric.Failover.Tests", "Test\DurableTask.ServiceFabric.Stress.Tests\DurableTask.ServiceFabric.Failover.Tests.csproj", "{BE4624F3-E565-428F-9EED-E6847530746A}" @@ -88,30 +82,6 @@ Global {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Release|Any CPU.Build.0 = Release|Any CPU {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Release|x64.ActiveCfg = Release|Any CPU {EDC63DDB-8397-4AEC-BF54-6395B2527075}.Release|x64.Build.0 = Release|Any CPU - {96980359-8003-4500-B97B-949A7FE01F31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {96980359-8003-4500-B97B-949A7FE01F31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {96980359-8003-4500-B97B-949A7FE01F31}.Debug|x64.ActiveCfg = Debug|Any CPU - {96980359-8003-4500-B97B-949A7FE01F31}.Debug|x64.Build.0 = Debug|Any CPU - {96980359-8003-4500-B97B-949A7FE01F31}.Release|Any CPU.ActiveCfg = Release|Any CPU - {96980359-8003-4500-B97B-949A7FE01F31}.Release|Any CPU.Build.0 = Release|Any CPU - {96980359-8003-4500-B97B-949A7FE01F31}.Release|x64.ActiveCfg = Release|Any CPU - {96980359-8003-4500-B97B-949A7FE01F31}.Release|x64.Build.0 = Release|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Debug|x64.ActiveCfg = Debug|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Debug|x64.Build.0 = Debug|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Release|Any CPU.Build.0 = Release|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Release|x64.ActiveCfg = Release|Any CPU - {6639DA74-9063-4A7C-9484-0A71C4FB5C18}.Release|x64.Build.0 = Release|Any CPU - {879670A7-919B-4AF9-8AFB-7C4EDAA0CC04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {879670A7-919B-4AF9-8AFB-7C4EDAA0CC04}.Debug|Any CPU.Build.0 = Debug|Any CPU - {879670A7-919B-4AF9-8AFB-7C4EDAA0CC04}.Debug|x64.ActiveCfg = Debug|Any CPU - {879670A7-919B-4AF9-8AFB-7C4EDAA0CC04}.Debug|x64.Build.0 = Debug|Any CPU - {879670A7-919B-4AF9-8AFB-7C4EDAA0CC04}.Release|Any CPU.ActiveCfg = Release|Any CPU - {879670A7-919B-4AF9-8AFB-7C4EDAA0CC04}.Release|Any CPU.Build.0 = Release|Any CPU - {879670A7-919B-4AF9-8AFB-7C4EDAA0CC04}.Release|x64.ActiveCfg = Release|Any CPU - {879670A7-919B-4AF9-8AFB-7C4EDAA0CC04}.Release|x64.Build.0 = Release|Any CPU {2BC2A5AD-4200-41B9-A034-332BB1D7187B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2BC2A5AD-4200-41B9-A034-332BB1D7187B}.Debug|Any CPU.Build.0 = Debug|Any CPU {2BC2A5AD-4200-41B9-A034-332BB1D7187B}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -159,9 +129,6 @@ Global {EA90334D-3194-4266-81EB-EECA9C760315} = {507C0CC2-082F-4EB7-8984-E2648976EB04} {5C617B24-4902-4992-8F71-AB14F00B74A8} = {0AE737F5-4AA1-402F-A61C-258CA00E282C} {EDC63DDB-8397-4AEC-BF54-6395B2527075} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} - {96980359-8003-4500-B97B-949A7FE01F31} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} - {6639DA74-9063-4A7C-9484-0A71C4FB5C18} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} - {879670A7-919B-4AF9-8AFB-7C4EDAA0CC04} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} {2BC2A5AD-4200-41B9-A034-332BB1D7187B} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} {BE4624F3-E565-428F-9EED-E6847530746A} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} {31C9C932-6376-46D4-A68A-A0A7F2726D38} = {5177D1DE-AC86-41B9-8D04-41988A7C2208} diff --git a/Test/DurableTask.ServiceFabric.Stress.Tests/DurableTask.ServiceFabric.Failover.Tests.csproj b/Test/DurableTask.ServiceFabric.Stress.Tests/DurableTask.ServiceFabric.Failover.Tests.csproj index 07283f157..af9297a5c 100644 --- a/Test/DurableTask.ServiceFabric.Stress.Tests/DurableTask.ServiceFabric.Failover.Tests.csproj +++ b/Test/DurableTask.ServiceFabric.Stress.Tests/DurableTask.ServiceFabric.Failover.Tests.csproj @@ -12,6 +12,8 @@ DurableTask.ServiceFabric.Failover.Tests 512 true + v4.5.1 + x64 @@ -22,6 +24,7 @@ DEBUG;TRACE prompt 4 + false x64 @@ -31,6 +34,7 @@ TRACE prompt 4 + false @@ -90,6 +94,10 @@ + + {6B386E8F-20EB-43DE-BBD7-6408A232B4BA} + DurableTask.Core + {2bc2a5ad-4200-41b9-a034-332bb1d7187b} DurableTask.Test.Orchestrations diff --git a/Test/DurableTask.ServiceFabric.Stress.Tests/OrchestrationRunner.cs b/Test/DurableTask.ServiceFabric.Stress.Tests/OrchestrationRunner.cs index f9ba25908..7d26bff37 100644 --- a/Test/DurableTask.ServiceFabric.Stress.Tests/OrchestrationRunner.cs +++ b/Test/DurableTask.ServiceFabric.Stress.Tests/OrchestrationRunner.cs @@ -19,6 +19,7 @@ namespace DurableTask.ServiceFabric.Failover.Tests using System.Diagnostics; using System.Threading; using System.Threading.Tasks; + using DurableTask.Core; using DurableTask.Test.Orchestrations.Perf; using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; diff --git a/Test/DurableTask.ServiceFabric.Stress.Tests/app.config b/Test/DurableTask.ServiceFabric.Stress.Tests/app.config index de5386a47..877e0c4b1 100644 --- a/Test/DurableTask.ServiceFabric.Stress.Tests/app.config +++ b/Test/DurableTask.ServiceFabric.Stress.Tests/app.config @@ -1,11 +1,11 @@ - + - - + + - \ No newline at end of file + diff --git a/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj b/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj index 62b7d9931..d741c8e25 100644 --- a/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj +++ b/Test/DurableTask.ServiceFabric.Test/DurableTask.ServiceFabric.Test.csproj @@ -11,6 +11,8 @@ DurableTask.ServiceFabric.Test DurableTask.ServiceFabric.Test 512 + v4.5.1 + true @@ -21,6 +23,7 @@ prompt 4 x64 + false pdbonly @@ -29,6 +32,7 @@ TRACE prompt 4 + false @@ -90,6 +94,10 @@ + + {6B386E8F-20EB-43DE-BBD7-6408A232B4BA} + DurableTask.Core + {5c617b24-4902-4992-8f71-ab14f00b74a8} DurableTask.ServiceFabric diff --git a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs index 80bb0b348..8f4ec6088 100644 --- a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs @@ -17,6 +17,7 @@ namespace DurableTask.ServiceFabric.Test using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; + using DurableTask.Core; using DurableTask.Test.Orchestrations.Perf; using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; diff --git a/Test/DurableTask.ServiceFabric.Test/StressTests.cs b/Test/DurableTask.ServiceFabric.Test/StressTests.cs index 714ebb3e3..6002af893 100644 --- a/Test/DurableTask.ServiceFabric.Test/StressTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/StressTests.cs @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; +using DurableTask.Core; using DurableTask.Test.Orchestrations.Perf; using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; diff --git a/Test/DurableTask.ServiceFabric.Test/WaitForOrchestrationTests.cs b/Test/DurableTask.ServiceFabric.Test/WaitForOrchestrationTests.cs index a10350233..29ac3f2cc 100644 --- a/Test/DurableTask.ServiceFabric.Test/WaitForOrchestrationTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/WaitForOrchestrationTests.cs @@ -15,6 +15,7 @@ namespace DurableTask.ServiceFabric.Test { using System; using System.Threading.Tasks; + using DurableTask.Core; using DurableTask.Test.Orchestrations.Perf; using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; diff --git a/Test/DurableTask.ServiceFabric.Test/app.config b/Test/DurableTask.ServiceFabric.Test/app.config index 10b73ca37..534e63b33 100644 --- a/Test/DurableTask.ServiceFabric.Test/app.config +++ b/Test/DurableTask.ServiceFabric.Test/app.config @@ -1,19 +1,19 @@ - + - - + + - - + + - - + + - \ No newline at end of file + diff --git a/Test/DurableTask.ServiceFabric.Tests.Tooling/DurableTask.ServiceFabric.Tests.Tooling.csproj b/Test/DurableTask.ServiceFabric.Tests.Tooling/DurableTask.ServiceFabric.Tests.Tooling.csproj index c344f8d8b..9cca2b322 100644 --- a/Test/DurableTask.ServiceFabric.Tests.Tooling/DurableTask.ServiceFabric.Tests.Tooling.csproj +++ b/Test/DurableTask.ServiceFabric.Tests.Tooling/DurableTask.ServiceFabric.Tests.Tooling.csproj @@ -9,9 +9,10 @@ Exe DurableTask.ServiceFabric.Tests.Tooling DurableTask.ServiceFabric.Tests.Tooling - v4.5.2 + v4.5.1 512 true + x64 @@ -85,9 +86,14 @@ + + + {6B386E8F-20EB-43DE-BBD7-6408A232B4BA} + DurableTask.Core + {ea90334d-3194-4266-81eb-eeca9c760315} TestApplication.Common diff --git a/Test/DurableTask.ServiceFabric.Tests.Tooling/Program.cs b/Test/DurableTask.ServiceFabric.Tests.Tooling/Program.cs index 12826ed9c..e6e21f7c2 100644 --- a/Test/DurableTask.ServiceFabric.Tests.Tooling/Program.cs +++ b/Test/DurableTask.ServiceFabric.Tests.Tooling/Program.cs @@ -15,6 +15,7 @@ namespace DurableTask.ServiceFabric.Tests.Tooling { using System; using System.Threading.Tasks; + using DurableTask.Core; using Microsoft.ServiceFabric.Services.Client; using Microsoft.ServiceFabric.Services.Remoting.Client; using TestApplication.Common; diff --git a/Test/DurableTask.ServiceFabric.Tests.Tooling/app.config b/Test/DurableTask.ServiceFabric.Tests.Tooling/app.config new file mode 100644 index 000000000..884f9844f --- /dev/null +++ b/Test/DurableTask.ServiceFabric.Tests.Tooling/app.config @@ -0,0 +1,3 @@ + + + diff --git a/Test/DurableTask.ServiceFabric.UnitTests/DurableTask.ServiceFabric.UnitTests.csproj b/Test/DurableTask.ServiceFabric.UnitTests/DurableTask.ServiceFabric.UnitTests.csproj index 407f73f74..be7bec0a9 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/DurableTask.ServiceFabric.UnitTests.csproj +++ b/Test/DurableTask.ServiceFabric.UnitTests/DurableTask.ServiceFabric.UnitTests.csproj @@ -11,6 +11,8 @@ DurableTask.ServiceFabric.UnitTests DurableTask.ServiceFabric.UnitTests 512 + v4.5.1 + true @@ -20,6 +22,7 @@ DEBUG;TRACE prompt 4 + false pdbonly @@ -28,12 +31,13 @@ TRACE prompt 4 + false - + False - ..\..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll + ..\..\packages\System.Collections.Immutable.1.5.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll True @@ -57,6 +61,10 @@ + + {6B386E8F-20EB-43DE-BBD7-6408A232B4BA} + DurableTask.Core + {5c617b24-4902-4992-8f71-ab14f00b74a8} DurableTask.ServiceFabric @@ -64,7 +72,9 @@ - + + Designer + diff --git a/Test/DurableTask.ServiceFabric.UnitTests/OrchestrationInstanceComparerTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/OrchestrationInstanceComparerTests.cs index bbbd8c12d..307b22a76 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/OrchestrationInstanceComparerTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/OrchestrationInstanceComparerTests.cs @@ -13,6 +13,7 @@ namespace DurableTask.ServiceFabric.UnitTests { + using DurableTask.Core; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] diff --git a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs index 3fbaf18c6..a6dd5541e 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs @@ -14,10 +14,8 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; -using System.IO; -using System.Runtime.Serialization; -using DurableTask.History; +using DurableTask.Core; +using DurableTask.Core.History; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace DurableTask.ServiceFabric.UnitTests diff --git a/Test/DurableTask.ServiceFabric.UnitTests/TaskMessageItemTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/TaskMessageItemTests.cs index ead5d2e7c..53830db32 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/TaskMessageItemTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/TaskMessageItemTests.cs @@ -11,7 +11,8 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using DurableTask.History; +using DurableTask.Core; +using DurableTask.Core.History; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace DurableTask.ServiceFabric.UnitTests diff --git a/Test/DurableTask.ServiceFabric.UnitTests/TimerFiredEventComparerTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/TimerFiredEventComparerTests.cs index 3b5fdff58..cfd084b24 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/TimerFiredEventComparerTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/TimerFiredEventComparerTests.cs @@ -13,7 +13,8 @@ using System; using System.Collections.Immutable; -using DurableTask.History; +using DurableTask.Core; +using DurableTask.Core.History; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace DurableTask.ServiceFabric.UnitTests diff --git a/Test/DurableTask.ServiceFabric.UnitTests/app.config b/Test/DurableTask.ServiceFabric.UnitTests/app.config index faaab9dc0..e51d1d527 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/app.config +++ b/Test/DurableTask.ServiceFabric.UnitTests/app.config @@ -1,15 +1,15 @@ - + - - + + - - + + - \ No newline at end of file + diff --git a/Test/DurableTask.ServiceFabric.UnitTests/packages.config b/Test/DurableTask.ServiceFabric.UnitTests/packages.config index 54d145ca3..f3a2d4d6d 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/packages.config +++ b/Test/DurableTask.ServiceFabric.UnitTests/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingActivity.cs b/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingActivity.cs index 9e9ffba2c..f41c7b1bf 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingActivity.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingActivity.cs @@ -14,6 +14,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using DurableTask.Core; namespace DurableTask.Test.Orchestrations.Perf { diff --git a/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingOrchestration.cs b/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingOrchestration.cs index 780d7ca89..de46e1cdf 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingOrchestration.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingOrchestration.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Threading.Tasks; +using DurableTask.Core; namespace DurableTask.Test.Orchestrations.Perf { diff --git a/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTask.cs b/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTask.cs index 7f21acd5c..73b672dff 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTask.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTask.cs @@ -13,6 +13,7 @@ using System; using System.Threading.Tasks; +using DurableTask.Core; namespace DurableTask.Test.Orchestrations.Perf { diff --git a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs index ce55e52ad..71d18a51d 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs @@ -19,7 +19,7 @@ namespace DurableTask.Test.Orchestrations.Perf using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; - using DurableTask; + using DurableTask.Core; public class TestOrchestration : TaskOrchestration { diff --git a/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs b/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs index a47ad0324..ca4afbd79 100644 --- a/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs +++ b/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs @@ -16,7 +16,7 @@ namespace TestApplication.Common using System; using System.Collections.Generic; using System.Threading.Tasks; - using DurableTask; + using DurableTask.Core; using DurableTask.Test.Orchestrations.Perf; using Microsoft.ServiceFabric.Services.Remoting; diff --git a/Test/TestFabricApplication/TestApplication.Common/TestApplication.Common.csproj b/Test/TestFabricApplication/TestApplication.Common/TestApplication.Common.csproj index 6b90643d6..91f58d5c2 100644 --- a/Test/TestFabricApplication/TestApplication.Common/TestApplication.Common.csproj +++ b/Test/TestFabricApplication/TestApplication.Common/TestApplication.Common.csproj @@ -98,6 +98,10 @@ + + {6B386E8F-20EB-43DE-BBD7-6408A232B4BA} + DurableTask.Core + {2bc2a5ad-4200-41b9-a034-332bb1d7187b} DurableTask.Test.Orchestrations diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/ExceptionThrowingTask.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/ExceptionThrowingTask.cs index 3cd406c14..4b0903ab1 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/ExceptionThrowingTask.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/ExceptionThrowingTask.cs @@ -11,7 +11,7 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using DurableTask; +using DurableTask.Core; namespace TestStatefulService.TestOrchestrations { diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GenerationBasicOrchestration.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GenerationBasicOrchestration.cs index 52c5f181e..202510118 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GenerationBasicOrchestration.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GenerationBasicOrchestration.cs @@ -12,7 +12,7 @@ // ---------------------------------------------------------------------------------- using System.Threading.Tasks; -using DurableTask; +using DurableTask.Core; namespace TestStatefulService.TestOrchestrations { diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GetUserTask.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GetUserTask.cs index fe8597deb..fc2a30324 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GetUserTask.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GetUserTask.cs @@ -11,7 +11,7 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using DurableTask; +using DurableTask.Core; namespace TestStatefulService.TestOrchestrations { diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GreetUserTask.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GreetUserTask.cs index 492b1b7de..f1cdd4d9f 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GreetUserTask.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GreetUserTask.cs @@ -11,7 +11,7 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using DurableTask; +using DurableTask.Core; namespace TestStatefulService.TestOrchestrations { diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/OrchestrationRunningIntoRetry.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/OrchestrationRunningIntoRetry.cs index 88e8dab16..3f394fe5e 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/OrchestrationRunningIntoRetry.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/OrchestrationRunningIntoRetry.cs @@ -12,10 +12,9 @@ // ---------------------------------------------------------------------------------- using System; -using System.Threading; using System.Threading.Tasks; -using DurableTask; -using DurableTask.Exceptions; +using DurableTask.Core; +using DurableTask.Core.Exceptions; namespace TestStatefulService.TestOrchestrations { diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithSubOrchestration.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithSubOrchestration.cs index 7ddc603d9..8633bc604 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithSubOrchestration.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithSubOrchestration.cs @@ -12,7 +12,7 @@ // ---------------------------------------------------------------------------------- using System.Threading.Tasks; -using DurableTask; +using DurableTask.Core; namespace TestStatefulService.TestOrchestrations { diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTasks.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTasks.cs index cbb93c8be..782f39c71 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTasks.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTasks.cs @@ -12,7 +12,7 @@ // ---------------------------------------------------------------------------------- using System.Threading.Tasks; -using DurableTask; +using DurableTask.Core; namespace TestStatefulService.TestOrchestrations { diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTimer.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTimer.cs index d421a5d1c..3fd2543b1 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTimer.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTimer.cs @@ -13,7 +13,7 @@ using System; using System.Threading.Tasks; -using DurableTask; +using DurableTask.Core; namespace TestStatefulService.TestOrchestrations { diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index 72c1e0029..f9608e002 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -17,7 +17,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using DurableTask; +using DurableTask.Core; using DurableTask.ServiceFabric; using DurableTask.Test.Orchestrations.Perf; using Microsoft.ServiceFabric.Services.Communication.Runtime; diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj index 07a326310..5ecfdb87f 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.csproj @@ -141,6 +141,10 @@ + + {6B386E8F-20EB-43DE-BBD7-6408A232B4BA} + DurableTask.Core + {5c617b24-4902-4992-8f71-ab14f00b74a8} DurableTask.ServiceFabric From 5f45e85e8272daf9d3f50289a7b29eaee0a83aa0 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Thu, 23 Aug 2018 17:09:12 -0700 Subject: [PATCH 205/210] This was needed to make the tests pass! --- .../FabricOrchestrationServiceClient.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index 726a4e6d8..eb3f0e7c5 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -75,7 +75,13 @@ public async Task CreateTaskOrchestrationAsync(TaskMessage creationMessage) public Task CreateTaskOrchestrationAsync(TaskMessage creationMessage, OrchestrationStatus[] dedupeStatuses) { - throw new NotImplementedException(); + // Todo: Support for dedupeStatuses? + if (dedupeStatuses != null) + { + throw new NotSupportedException($"DedupeStatuses are not supported yet with service fabric provider"); + } + + return CreateTaskOrchestrationAsync(creationMessage); } public Task SendTaskOrchestrationMessageAsync(TaskMessage message) @@ -83,9 +89,12 @@ public Task SendTaskOrchestrationMessageAsync(TaskMessage message) return this.orchestrationProvider.AppendMessageAsync(new TaskMessageItem(message)); } - public Task SendTaskOrchestrationMessageBatchAsync(params TaskMessage[] messages) + public async Task SendTaskOrchestrationMessageBatchAsync(params TaskMessage[] messages) { - throw new NotImplementedException(); + foreach(var message in messages) + { + await this.SendTaskOrchestrationMessageAsync(message); + } } public async Task ForceTerminateTaskOrchestrationAsync(string instanceId, string reason) From 94502332c9f2a93f5be6a6103b22d0a4b7881dc2 Mon Sep 17 00:00:00 2001 From: prasanna gunuru Date: Fri, 7 Sep 2018 17:54:00 -0700 Subject: [PATCH 206/210] PR Comment1: Move the usings in all files inside the namespace statement. --- .../AssemblySetup.cs | 10 +++---- .../DeploymentUtil/ApplicationInfoReader.cs | 10 +++---- .../DeploymentUtil/DeploymentHelper.cs | 18 +++++------ .../StressTests.cs | 22 +++++++------- .../CountBasedFixedDelayRetryPolicyTests.cs | 6 ++-- .../Measure.cs | 10 +++---- .../PersistentSessionTests.cs | 14 ++++----- .../SerializationPerformanceExperiments.cs | 12 ++++---- .../TaskMessageItemTests.cs | 8 ++--- .../TimerFiredEventComparerTests.cs | 12 ++++---- .../TestApplication.Common/IOwinAppBuilder.cs | 4 +-- .../OwinCommunicationListener.cs | 20 ++++++------- .../TestStatefulService/Program.cs | 10 +++---- .../TestStatefulService/ServiceEventSource.cs | 10 +++---- .../TestStatefulService/Startup.cs | 8 ++--- .../TestOrchestrations/CounterException.cs | 6 ++-- .../ExceptionThrowingTask.cs | 4 +-- .../GenerationBasicOrchestration.cs | 6 ++-- .../TestOrchestrations/GetUserTask.cs | 4 +-- .../TestOrchestrations/GreetUserTask.cs | 4 +-- .../OrchestrationRunningIntoRetry.cs | 10 +++---- ...SimpleOrchestrationWithSubOrchestration.cs | 6 ++-- .../SimpleOrchestrationWithTasks.cs | 6 ++-- .../SimpleOrchestrationWithTimer.cs | 8 ++--- .../TestStatefulService.cs | 30 +++++++++---------- 25 files changed, 129 insertions(+), 129 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.Test/AssemblySetup.cs b/Test/DurableTask.ServiceFabric.Test/AssemblySetup.cs index 9776be272..ce7be91a8 100644 --- a/Test/DurableTask.ServiceFabric.Test/AssemblySetup.cs +++ b/Test/DurableTask.ServiceFabric.Test/AssemblySetup.cs @@ -11,13 +11,13 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.IO; -using DurableTask.ServiceFabric.Test.DeploymentUtil; -using Microsoft.VisualStudio.TestTools.UnitTesting; - namespace DurableTask.ServiceFabric.Test { + using System; + using System.IO; + using DurableTask.ServiceFabric.Test.DeploymentUtil; + using Microsoft.VisualStudio.TestTools.UnitTesting; + [TestClass] public class AssemblySetup { diff --git a/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/ApplicationInfoReader.cs b/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/ApplicationInfoReader.cs index 773fb3206..34d66d046 100644 --- a/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/ApplicationInfoReader.cs +++ b/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/ApplicationInfoReader.cs @@ -11,13 +11,13 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System.Collections.Specialized; -using System.IO; -using System.Linq; -using System.Xml; - namespace DurableTask.ServiceFabric.Test.DeploymentUtil { + using System.Collections.Specialized; + using System.IO; + using System.Linq; + using System.Xml; + class ApplicationInfoReader { string applicationRootPath; diff --git a/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/DeploymentHelper.cs b/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/DeploymentHelper.cs index b68bebf6e..1335bea37 100644 --- a/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/DeploymentHelper.cs +++ b/Test/DurableTask.ServiceFabric.Test/DeploymentUtil/DeploymentHelper.cs @@ -11,17 +11,17 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Fabric; -using System.Fabric.Description; -using System.Fabric.Health; -using System.Fabric.Query; -using System.Linq; -using System.Threading.Tasks; -using System.Xml; - namespace DurableTask.ServiceFabric.Test.DeploymentUtil { + using System; + using System.Fabric; + using System.Fabric.Description; + using System.Fabric.Health; + using System.Fabric.Query; + using System.Linq; + using System.Threading.Tasks; + using System.Xml; + static class DeploymentHelper { static readonly FabricClient client = new FabricClient(); diff --git a/Test/DurableTask.ServiceFabric.Test/StressTests.cs b/Test/DurableTask.ServiceFabric.Test/StressTests.cs index 6002af893..bddd4c53f 100644 --- a/Test/DurableTask.ServiceFabric.Test/StressTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/StressTests.cs @@ -11,19 +11,19 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading.Tasks; -using DurableTask.Core; -using DurableTask.Test.Orchestrations.Perf; -using Microsoft.ServiceFabric.Services.Client; -using Microsoft.ServiceFabric.Services.Remoting.Client; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using TestApplication.Common; - namespace DurableTask.ServiceFabric.Test { + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Threading.Tasks; + using DurableTask.Core; + using DurableTask.Test.Orchestrations.Perf; + using Microsoft.ServiceFabric.Services.Client; + using Microsoft.ServiceFabric.Services.Remoting.Client; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using TestApplication.Common; + [TestClass] public class StressTests { diff --git a/Test/DurableTask.ServiceFabric.UnitTests/CountBasedFixedDelayRetryPolicyTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/CountBasedFixedDelayRetryPolicyTests.cs index c2ea8239b..3856a91c0 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/CountBasedFixedDelayRetryPolicyTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/CountBasedFixedDelayRetryPolicyTests.cs @@ -11,11 +11,11 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using Microsoft.VisualStudio.TestTools.UnitTesting; - namespace DurableTask.ServiceFabric.UnitTests { + using System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + [TestClass] public class CountBasedFixedDelayRetryPolicyTests { diff --git a/Test/DurableTask.ServiceFabric.UnitTests/Measure.cs b/Test/DurableTask.ServiceFabric.UnitTests/Measure.cs index 0e842b400..b8558834b 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/Measure.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/Measure.cs @@ -11,13 +11,13 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Diagnostics; -using System.IO; -using System.Runtime.Serialization; - namespace DurableTask.ServiceFabric.UnitTests { + using System; + using System.Diagnostics; + using System.IO; + using System.Runtime.Serialization; + class Measure { public static T DataContractSerialization(T testObject) diff --git a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs index a6dd5541e..bdc74243e 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/PersistentSessionTests.cs @@ -11,15 +11,15 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using DurableTask.Core; -using DurableTask.Core.History; -using Microsoft.VisualStudio.TestTools.UnitTesting; - namespace DurableTask.ServiceFabric.UnitTests { + using System; + using System.Collections.Generic; + using System.Collections.Immutable; + using DurableTask.Core; + using DurableTask.Core.History; + using Microsoft.VisualStudio.TestTools.UnitTesting; + [TestClass] public class PersistentSessionTests { diff --git a/Test/DurableTask.ServiceFabric.UnitTests/SerializationPerformanceExperiments.cs b/Test/DurableTask.ServiceFabric.UnitTests/SerializationPerformanceExperiments.cs index 8a1f2e67f..df2bc5e17 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/SerializationPerformanceExperiments.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/SerializationPerformanceExperiments.cs @@ -11,14 +11,14 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.Serialization; -using Microsoft.VisualStudio.TestTools.UnitTesting; - namespace DurableTask.ServiceFabric.UnitTests { + using System; + using System.Collections.Generic; + using System.IO; + using System.Runtime.Serialization; + using Microsoft.VisualStudio.TestTools.UnitTesting; + [TestClass] public class SerializationPerformanceExperiments { diff --git a/Test/DurableTask.ServiceFabric.UnitTests/TaskMessageItemTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/TaskMessageItemTests.cs index 53830db32..2881a08f2 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/TaskMessageItemTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/TaskMessageItemTests.cs @@ -11,12 +11,12 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using DurableTask.Core; -using DurableTask.Core.History; -using Microsoft.VisualStudio.TestTools.UnitTesting; - namespace DurableTask.ServiceFabric.UnitTests { + using DurableTask.Core; + using DurableTask.Core.History; + using Microsoft.VisualStudio.TestTools.UnitTesting; + [TestClass] public class TaskMessageItemTests { diff --git a/Test/DurableTask.ServiceFabric.UnitTests/TimerFiredEventComparerTests.cs b/Test/DurableTask.ServiceFabric.UnitTests/TimerFiredEventComparerTests.cs index cfd084b24..d24fd2aa3 100644 --- a/Test/DurableTask.ServiceFabric.UnitTests/TimerFiredEventComparerTests.cs +++ b/Test/DurableTask.ServiceFabric.UnitTests/TimerFiredEventComparerTests.cs @@ -11,14 +11,14 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Collections.Immutable; -using DurableTask.Core; -using DurableTask.Core.History; -using Microsoft.VisualStudio.TestTools.UnitTesting; - namespace DurableTask.ServiceFabric.UnitTests { + using System; + using System.Collections.Immutable; + using DurableTask.Core; + using DurableTask.Core.History; + using Microsoft.VisualStudio.TestTools.UnitTesting; + [TestClass] public class TimerFiredEventComparerTests { diff --git a/Test/TestFabricApplication/TestApplication.Common/IOwinAppBuilder.cs b/Test/TestFabricApplication/TestApplication.Common/IOwinAppBuilder.cs index 2d3ccebc2..bfd7d02e4 100644 --- a/Test/TestFabricApplication/TestApplication.Common/IOwinAppBuilder.cs +++ b/Test/TestFabricApplication/TestApplication.Common/IOwinAppBuilder.cs @@ -11,10 +11,10 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using Owin; - namespace TestApplication.Common { + using Owin; + public interface IOwinAppBuilder { void Configuration(IAppBuilder appBuilder); diff --git a/Test/TestFabricApplication/TestApplication.Common/OwinCommunicationListener.cs b/Test/TestFabricApplication/TestApplication.Common/OwinCommunicationListener.cs index 40e38e6ca..4726521b9 100644 --- a/Test/TestFabricApplication/TestApplication.Common/OwinCommunicationListener.cs +++ b/Test/TestFabricApplication/TestApplication.Common/OwinCommunicationListener.cs @@ -11,18 +11,18 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Diagnostics; -using System.Fabric; -using System.Fabric.Description; -using System.Globalization; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Owin.Hosting; -using Microsoft.ServiceFabric.Services.Communication.Runtime; - namespace TestApplication.Common { + using System; + using System.Diagnostics; + using System.Fabric; + using System.Fabric.Description; + using System.Globalization; + using System.Threading; + using System.Threading.Tasks; + using Microsoft.Owin.Hosting; + using Microsoft.ServiceFabric.Services.Communication.Runtime; + public class OwinCommunicationListener : ICommunicationListener { private readonly ServiceContext serviceContext; diff --git a/Test/TestFabricApplication/TestStatefulService/Program.cs b/Test/TestFabricApplication/TestStatefulService/Program.cs index 7f1d0b60b..c5f965b25 100644 --- a/Test/TestFabricApplication/TestStatefulService/Program.cs +++ b/Test/TestFabricApplication/TestStatefulService/Program.cs @@ -11,13 +11,13 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Diagnostics; -using System.Threading; -using Microsoft.ServiceFabric.Services.Runtime; - namespace TestStatefulService { + using System; + using System.Diagnostics; + using System.Threading; + using Microsoft.ServiceFabric.Services.Runtime; + internal static class Program { /// diff --git a/Test/TestFabricApplication/TestStatefulService/ServiceEventSource.cs b/Test/TestFabricApplication/TestStatefulService/ServiceEventSource.cs index fe03207b8..b1a8eb848 100644 --- a/Test/TestFabricApplication/TestStatefulService/ServiceEventSource.cs +++ b/Test/TestFabricApplication/TestStatefulService/ServiceEventSource.cs @@ -11,13 +11,13 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Diagnostics.Tracing; -using System.Threading.Tasks; -using Microsoft.ServiceFabric.Services.Runtime; - namespace TestStatefulService { + using System; + using System.Diagnostics.Tracing; + using System.Threading.Tasks; + using Microsoft.ServiceFabric.Services.Runtime; + [EventSource(Name = "MyCompany-TestFabricApplication-TestStatefulService")] internal sealed class ServiceEventSource : EventSource { diff --git a/Test/TestFabricApplication/TestStatefulService/Startup.cs b/Test/TestFabricApplication/TestStatefulService/Startup.cs index 6c84c4c1a..f371d998e 100644 --- a/Test/TestFabricApplication/TestStatefulService/Startup.cs +++ b/Test/TestFabricApplication/TestStatefulService/Startup.cs @@ -11,12 +11,12 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System.Web.Http; -using Owin; -using TestApplication.Common; - namespace TestStatefulService { + using System.Web.Http; + using Owin; + using TestApplication.Common; + class Startup : IOwinAppBuilder { public void Configuration(IAppBuilder appBuilder) diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/CounterException.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/CounterException.cs index 6ec96282c..2854d6895 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/CounterException.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/CounterException.cs @@ -11,11 +11,11 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Runtime.Serialization; - namespace TestStatefulService.TestOrchestrations { + using System; + using System.Runtime.Serialization; + [Serializable] public class CounterException : Exception { diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/ExceptionThrowingTask.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/ExceptionThrowingTask.cs index 4b0903ab1..b23bf45a6 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/ExceptionThrowingTask.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/ExceptionThrowingTask.cs @@ -11,10 +11,10 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using DurableTask.Core; - namespace TestStatefulService.TestOrchestrations { + using DurableTask.Core; + class ExceptionThrowingTask : TaskActivity { protected override bool Execute(TaskContext context, int remainingAttempts) diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GenerationBasicOrchestration.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GenerationBasicOrchestration.cs index 202510118..91896b1b6 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GenerationBasicOrchestration.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GenerationBasicOrchestration.cs @@ -11,11 +11,11 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System.Threading.Tasks; -using DurableTask.Core; - namespace TestStatefulService.TestOrchestrations { + using System.Threading.Tasks; + using DurableTask.Core; + public class GenerationBasicOrchestration : TaskOrchestration { // HACK: This is just a hack to communicate result of orchestration back to test diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GetUserTask.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GetUserTask.cs index fc2a30324..0251db70c 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GetUserTask.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GetUserTask.cs @@ -11,10 +11,10 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using DurableTask.Core; - namespace TestStatefulService.TestOrchestrations { + using DurableTask.Core; + class GetUserTask : TaskActivity { protected override string Execute(TaskContext context, string input) diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GreetUserTask.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GreetUserTask.cs index f1cdd4d9f..6a35c553c 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GreetUserTask.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/GreetUserTask.cs @@ -11,10 +11,10 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using DurableTask.Core; - namespace TestStatefulService.TestOrchestrations { + using DurableTask.Core; + class GreetUserTask : TaskActivity { protected override string Execute(TaskContext context, string user) diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/OrchestrationRunningIntoRetry.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/OrchestrationRunningIntoRetry.cs index 3f394fe5e..cbf400cf5 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/OrchestrationRunningIntoRetry.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/OrchestrationRunningIntoRetry.cs @@ -11,13 +11,13 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Threading.Tasks; -using DurableTask.Core; -using DurableTask.Core.Exceptions; - namespace TestStatefulService.TestOrchestrations { + using System; + using System.Threading.Tasks; + using DurableTask.Core; + using DurableTask.Core.Exceptions; + public class OrchestrationRunningIntoRetry : TaskOrchestration { CounterException LatestException; diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithSubOrchestration.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithSubOrchestration.cs index 8633bc604..4b94cc0d3 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithSubOrchestration.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithSubOrchestration.cs @@ -11,11 +11,11 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System.Threading.Tasks; -using DurableTask.Core; - namespace TestStatefulService.TestOrchestrations { + using System.Threading.Tasks; + using DurableTask.Core; + public class SimpleOrchestrationWithSubOrchestration : TaskOrchestration { public override async Task RunTask(OrchestrationContext context, string input) diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTasks.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTasks.cs index 782f39c71..db424a550 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTasks.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTasks.cs @@ -11,11 +11,11 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System.Threading.Tasks; -using DurableTask.Core; - namespace TestStatefulService.TestOrchestrations { + using System.Threading.Tasks; + using DurableTask.Core; + public class SimpleOrchestrationWithTasks : TaskOrchestration { public override async Task RunTask(OrchestrationContext context, string input) diff --git a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTimer.cs b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTimer.cs index 3fd2543b1..dc03181bc 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTimer.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestOrchestrations/SimpleOrchestrationWithTimer.cs @@ -11,12 +11,12 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Threading.Tasks; -using DurableTask.Core; - namespace TestStatefulService.TestOrchestrations { + using System; + using System.Threading.Tasks; + using DurableTask.Core; + public class SimpleOrchestrationWithTimer : TaskOrchestration { public override async Task RunTask(OrchestrationContext context, int input) diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index f9608e002..0e59b37d5 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -11,23 +11,23 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Collections.Generic; -using System.Fabric; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using DurableTask.Core; -using DurableTask.ServiceFabric; -using DurableTask.Test.Orchestrations.Perf; -using Microsoft.ServiceFabric.Services.Communication.Runtime; -using Microsoft.ServiceFabric.Services.Remoting.Runtime; -using Microsoft.ServiceFabric.Services.Runtime; -using TestApplication.Common; -using TestStatefulService.TestOrchestrations; - namespace TestStatefulService { + using System; + using System.Collections.Generic; + using System.Fabric; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + using DurableTask.Core; + using DurableTask.ServiceFabric; + using DurableTask.Test.Orchestrations.Perf; + using Microsoft.ServiceFabric.Services.Communication.Runtime; + using Microsoft.ServiceFabric.Services.Remoting.Runtime; + using Microsoft.ServiceFabric.Services.Runtime; + using TestApplication.Common; + using TestStatefulService.TestOrchestrations; + /// /// An instance of this class is created for each service replica by the Service Fabric runtime. /// From 18d7090405dae7e414d3e01ddc5d8004ad380f35 Mon Sep 17 00:00:00 2001 From: PradeepKadubandi Date: Fri, 2 Nov 2018 14:42:39 -0700 Subject: [PATCH 207/210] CR comment : Move usings inside namespace. --- .../Perf/DriverOrchestrationData.cs | 4 ++-- .../Perf/ExecutionCountingActivity.cs | 10 +++++----- .../Perf/ExecutionCountingOrchestration.cs | 8 ++++---- .../Perf/RandomTimeWaitingTask.cs | 8 ++++---- .../Perf/RandomTimeWaitingTaskInput.cs | 4 ++-- .../Perf/TestOrchestration.cs | 5 ++--- .../Perf/TestOrchestrationData.cs | 6 +++--- src/DurableTask.ServiceFabric/Message.cs | 1 - 8 files changed, 22 insertions(+), 24 deletions(-) diff --git a/Test/DurableTask.Test.Orchestrations/Perf/DriverOrchestrationData.cs b/Test/DurableTask.Test.Orchestrations/Perf/DriverOrchestrationData.cs index b77bab465..e8d626e94 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/DriverOrchestrationData.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/DriverOrchestrationData.cs @@ -11,10 +11,10 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System.Runtime.Serialization; - namespace DurableTask.Test.Orchestrations.Perf { + using System.Runtime.Serialization; + [DataContract] [KnownType(typeof(DriverOrchestrationData))] public class DriverOrchestrationData diff --git a/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingActivity.cs b/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingActivity.cs index f41c7b1bf..12e4f3e26 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingActivity.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingActivity.cs @@ -11,13 +11,13 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Threading; -using System.Threading.Tasks; -using DurableTask.Core; - namespace DurableTask.Test.Orchestrations.Perf { + using System; + using System.Threading; + using System.Threading.Tasks; + using DurableTask.Core; + public sealed class ExecutionCountingActivity : AsyncTaskActivity { // This has to be reset before starting the orchestration and the orchestration diff --git a/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingOrchestration.cs b/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingOrchestration.cs index de46e1cdf..0c309a757 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingOrchestration.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/ExecutionCountingOrchestration.cs @@ -11,12 +11,12 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System.Collections.Generic; -using System.Threading.Tasks; -using DurableTask.Core; - namespace DurableTask.Test.Orchestrations.Perf { + using System.Collections.Generic; + using System.Threading.Tasks; + using DurableTask.Core; + public sealed class ExecutionCountingOrchestration : TaskOrchestration { public override async Task RunTask(OrchestrationContext context, int numberOfActivities) diff --git a/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTask.cs b/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTask.cs index 73b672dff..392e8feca 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTask.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTask.cs @@ -11,12 +11,12 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Threading.Tasks; -using DurableTask.Core; - namespace DurableTask.Test.Orchestrations.Perf { + using System; + using System.Threading.Tasks; + using DurableTask.Core; + public sealed class RandomTimeWaitingTask : AsyncTaskActivity { protected override async Task ExecuteAsync(TaskContext context, RandomTimeWaitingTaskInput input) diff --git a/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTaskInput.cs b/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTaskInput.cs index 872722c91..395a41e68 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTaskInput.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/RandomTimeWaitingTaskInput.cs @@ -11,10 +11,10 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; - namespace DurableTask.Test.Orchestrations.Perf { + using System; + public class RandomTimeWaitingTaskInput { public string TaskId { get; set; } diff --git a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs index 71d18a51d..df44a1a2d 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestration.cs @@ -11,15 +11,14 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System.Threading; - namespace DurableTask.Test.Orchestrations.Perf { + using DurableTask.Core; using System; using System.Collections.Generic; using System.Linq; + using System.Threading; using System.Threading.Tasks; - using DurableTask.Core; public class TestOrchestration : TaskOrchestration { diff --git a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestrationData.cs b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestrationData.cs index 0b4e18ff7..92a34fa07 100644 --- a/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestrationData.cs +++ b/Test/DurableTask.Test.Orchestrations/Perf/TestOrchestrationData.cs @@ -11,11 +11,11 @@ // limitations under the License. // ---------------------------------------------------------------------------------- -using System; -using System.Runtime.Serialization; - namespace DurableTask.Test.Orchestrations.Perf { + using System; + using System.Runtime.Serialization; + [DataContract] [KnownType(typeof(TestOrchestrationData))] public class TestOrchestrationData diff --git a/src/DurableTask.ServiceFabric/Message.cs b/src/DurableTask.ServiceFabric/Message.cs index b62d6a2a4..acf4b375f 100644 --- a/src/DurableTask.ServiceFabric/Message.cs +++ b/src/DurableTask.ServiceFabric/Message.cs @@ -14,7 +14,6 @@ namespace DurableTask.ServiceFabric { using System; - using System.Runtime.Serialization; sealed class Message where TKey : IComparable, IEquatable { From dd3e02d8fac598615cd9106e4a9cc9738ca0a9a4 Mon Sep 17 00:00:00 2001 From: PradeepKadubandi Date: Fri, 2 Nov 2018 15:15:59 -0700 Subject: [PATCH 208/210] CR Comment : Skipping InternalsVisibleTo attributes when signing assemblies for build. --- src/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs b/src/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs index c91191876..15f589a18 100644 --- a/src/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs +++ b/src/DurableTask.ServiceFabric/Properties/AssemblyInfo.cs @@ -1,3 +1,5 @@ using System.Runtime.CompilerServices; +#if !SIGN_ASSEMBLY [assembly: InternalsVisibleTo("DurableTask.ServiceFabric.UnitTests")] +#endif \ No newline at end of file From 6cba6471eed5d33ce3aac50be7f843db69eb83ef Mon Sep 17 00:00:00 2001 From: PradeepKadubandi Date: Mon, 17 Dec 2018 16:12:02 -0800 Subject: [PATCH 209/210] Minor fix needed to make the tests pass! --- .../TestStatefulService/TestStatefulService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index 0e59b37d5..544fc9d06 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -26,7 +26,7 @@ namespace TestStatefulService using Microsoft.ServiceFabric.Services.Remoting.Runtime; using Microsoft.ServiceFabric.Services.Runtime; using TestApplication.Common; - using TestStatefulService.TestOrchestrations; + using TestOrchestrations; /// /// An instance of this class is created for each service replica by the Service Fabric runtime. From de31204c62679585e3977271ca9d802872b296a2 Mon Sep 17 00:00:00 2001 From: Pradeep Kadubandi Date: Thu, 20 Jun 2019 01:26:16 +0000 Subject: [PATCH 210/210] Support for ContinueForNew feature. (Querying for orchestration state across executions is still not supported though). Detailed commit notes/history below: Squashed commit of the following: commit 8d31731d0eab26559a6f63478995c3ba36d30f1a Author: Pradeep Kadubandi Date: Thu Jun 20 01:24:02 2019 +0000 Fixing a minor overlook. commit 26362eb11d4d03fb1c964e035721773c76c6cfaf Author: Pradeep Kadubandi Date: Wed Jun 19 23:35:18 2019 +0000 After reviewing the service bus client functionality for WaitForOrchestation client API which ignores the input executionId and instead wait for latest execution id of given orchestration, I changed the fabric provider client's implementation to match that. The fabric provider still does not support querying for orchestration state across all executions. To implement that, we perhaps needs to introduce one more dictionary to track all execution ids for a given orchestration instance. There are some open questions about this like should we differentiate the executions from ContinueAsNew to that of different executions caused by user creating the orchestration with same instanceId after the current one completes. Also it's not clear if this functionality is desired at all. So until I hear otherwise, I choose to postpone it. commit 5a79296006f893aed9a996ecf9c676af76ee1ee7 Author: Pradeep Kadubandi Date: Tue Jun 18 01:25:03 2019 +0000 More changes after testing the Contnued Orchestration Functionality. These changes work on the TaskHub side (i.e., Continued orchestration runs as expected) as seen in debugging. However, the instance store still requires some changes - for ContinueAsNew support to make sense, we probably should support querying for state across all executions? commit 6f0fa962845d7ff02d628a66eea6949f1bbbc782 Author: Pradeep Kadubandi Date: Mon Jun 17 22:53:52 2019 +0000 Initial change to enable ContinueAsNew. Also enabling the existing basic functional test for ContinusAsNew. There are still at least 2 issues to follow through: - It seems to me that the old execution should be fine. The status of Orchestration when queried for that specific execution comes out as 'ContinuedAsNew' which is probably correct. However, I still need to confirm that the new execution works as expected (with the current test, as soon as old execution is completed, the test exits killing the fabric application making it harder to understand). - The instance store does not support traking the state over multiple executions. Without this, there is no way to get the latest history for a given orchstration with one instance id and latest execution. --- .../FunctionalTests.cs | 8 ++--- .../TestApplication.Common/IRemoteClient.cs | 2 ++ .../TestStatefulService.cs | 8 ++++- .../FabricOrchestrationInstanceStore.cs | 30 +++++++++++-------- .../FabricOrchestrationService.cs | 25 ++++++++++------ .../FabricOrchestrationServiceClient.cs | 20 +++++++++++-- ...FabricOrchestrationServiceInstanceStore.cs | 2 +- 7 files changed, 65 insertions(+), 30 deletions(-) diff --git a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs index 8f4ec6088..37701516b 100644 --- a/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs +++ b/Test/DurableTask.ServiceFabric.Test/FunctionalTests.cs @@ -59,16 +59,14 @@ public async Task Orchestration_With_Timer_Finishes_After_The_Wait_Time() } [TestMethod] - [Ignore] public async Task GenerationBasicTest() { - GenerationBasicOrchestration.Result = 0; - GenerationBasicTask.GenerationCount = 0; + int generationsToRun = 2; - var result = await this.serviceClient.RunOrchestrationAsync(typeof(GenerationBasicOrchestration).Name, 4, TimeSpan.FromMinutes(2)); + var result = await this.serviceClient.RunOrchestrationAsync(typeof(GenerationBasicOrchestration).Name, generationsToRun, TimeSpan.FromMinutes(2)); Assert.AreEqual(OrchestrationStatus.Completed, result.OrchestrationStatus); - Assert.AreEqual(4, GenerationBasicOrchestration.Result, "Orchestration Result is wrong!!!"); + Assert.AreEqual(generationsToRun.ToString(), result.Output, "Orchestration Result is wrong!!!"); } [TestMethod] diff --git a/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs b/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs index ca4afbd79..5cc34574e 100644 --- a/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs +++ b/Test/TestFabricApplication/TestApplication.Common/IRemoteClient.cs @@ -26,6 +26,8 @@ public interface IRemoteClient : IService Task GetOrchestrationRuntimeState(string instanceId); + Task StartOrchestrationAsync(string orchestrationTypeName, object input); + Task RunOrchestrationAsync(string orchestrationTypeName, object input, TimeSpan waitTimeout); Task RunDriverOrchestrationAsync(DriverOrchestrationData input, TimeSpan waitTimeout); diff --git a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs index 544fc9d06..18eb1c9c0 100644 --- a/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs +++ b/Test/TestFabricApplication/TestStatefulService/TestStatefulService.cs @@ -109,6 +109,12 @@ protected override async Task OnCloseAsync(CancellationToken cancellationToken) } public async Task RunOrchestrationAsync(string orchestrationTypeName, object input, TimeSpan waitTimeout) + { + OrchestrationInstance instance = await StartOrchestrationAsync(orchestrationTypeName, input); + return await client.WaitForOrchestrationAsync(instance, waitTimeout); + } + + public async Task StartOrchestrationAsync(string orchestrationTypeName, object input) { if (orchestrationTypeName == typeof(ExecutionCountingOrchestration).Name) { @@ -117,7 +123,7 @@ public async Task RunOrchestrationAsync(string orchestration } var instance = await client.CreateOrchestrationInstanceAsync(GetOrchestrationType(orchestrationTypeName), input); - return await client.WaitForOrchestrationAsync(instance, waitTimeout); + return instance; } public async Task RunDriverOrchestrationAsync(DriverOrchestrationData input, TimeSpan waitTimeout) diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs index 00db5c27d..54e46e853 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationInstanceStore.cs @@ -18,6 +18,7 @@ namespace DurableTask.ServiceFabric using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; + using System.Linq; using System.Threading; using System.Threading.Tasks; using DurableTask.Core; @@ -36,7 +37,7 @@ class FabricOrchestrationInstanceStore : IFabricOrchestrationServiceInstanceStor const string TimeFormatStringPrefix = "yyyy-MM-dd-"; readonly IReliableStateManager stateManager; readonly CancellationToken cancellationToken; - readonly ConcurrentDictionary orchestrationWaiters = new ConcurrentDictionary(OrchestrationInstanceComparer.Default); + readonly ConcurrentDictionary orchestrationWaiters = new ConcurrentDictionary(StringComparer.Ordinal); IReliableDictionary instanceStore; IReliableDictionary executionIdStore; @@ -82,10 +83,7 @@ public async Task WriteEntitesAsync(ITransaction transaction, IEnumerable instance.ExecutionId); - } + await this.executionIdStore.AddOrUpdateAsync(transaction, instance.InstanceId, instance.ExecutionId, (k, old) => instance.ExecutionId); await this.instanceStore.AddOrUpdateAsync(transaction, key, state.State, (k, oldValue) => state.State); } @@ -133,8 +131,9 @@ public async Task> GetOrchestrationState public async Task GetLatestExecutionId(string instanceId) { - string latestExecutionId = null; + await this.EnsureStoreInitialized(); + string latestExecutionId = null; await RetryHelper.ExecuteWithRetryOnTransient(async () => { using (var tx = this.stateManager.CreateTransaction()) @@ -315,9 +314,15 @@ async Task EnsureStoreInitialized() } } - public async Task WaitForOrchestrationAsync(OrchestrationInstance instance, TimeSpan timeout) + public async Task WaitForOrchestrationAsync(string instanceId, TimeSpan timeout) { - var currentState = await this.GetOrchestrationStateAsync(instance.InstanceId, instance.ExecutionId); + var executionId = await this.GetLatestExecutionId(instanceId); + if (executionId == null) + { + return null; + } + + var currentState = await this.GetOrchestrationStateAsync(instanceId, executionId); // If querying state for an orchestration that's not started or completed and state cleaned up, we will immediately return null. if (currentState?.State == null) @@ -330,15 +335,16 @@ public async Task WaitForOrchestrationAsync(Or return currentState; } - var waiter = this.orchestrationWaiters.GetOrAdd(instance, new AsyncManualResetEvent()); + var waiter = this.orchestrationWaiters.GetOrAdd(instanceId, new AsyncManualResetEvent()); bool completed = await waiter.WaitAsync(timeout, this.cancellationToken); if (!completed) { - this.orchestrationWaiters.TryRemove(instance, out waiter); + this.orchestrationWaiters.TryRemove(instanceId, out waiter); } - currentState = await this.GetOrchestrationStateAsync(instance.InstanceId, instance.ExecutionId); + var latestStates = await this.GetOrchestrationStateAsync(instanceId, allInstances: false); + currentState = latestStates.FirstOrDefault(); if (currentState?.State != null && currentState.State.OrchestrationStatus.IsTerminalState()) { return currentState; @@ -350,7 +356,7 @@ public async Task WaitForOrchestrationAsync(Or public void OnOrchestrationCompleted(OrchestrationInstance instance) { AsyncManualResetEvent resetEvent; - if (this.orchestrationWaiters.TryRemove(instance, out resetEvent)) + if (this.orchestrationWaiters.TryRemove(instance.InstanceId, out resetEvent)) { resetEvent.Set(); } diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs index a4e8c1dbf..41e01e315 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationService.cs @@ -160,7 +160,7 @@ public async Task LockNextTaskOrchestrationWorkItemAs return null; } - bool isComplete = currentRuntimeState.OrchestrationStatus.IsTerminalState(); + bool isComplete = this.IsOrchestrationComplete(currentRuntimeState.OrchestrationStatus); if (isComplete) { await this.HandleCompletedOrchestration(workItem); @@ -206,12 +206,7 @@ public async Task CompleteTaskOrchestrationWorkItemAsync( { SessionInformation sessionInfo = GetSessionInfo(workItem.InstanceId); - if (continuedAsNewMessage != null) - { - throw new Exception("ContinueAsNew is not supported yet"); - } - - bool isComplete = workItem.OrchestrationRuntimeState.OrchestrationStatus.IsTerminalState(); + bool isComplete = this.IsOrchestrationComplete(workItem.OrchestrationRuntimeState.OrchestrationStatus); IList sessionsToEnqueue = null; List> scheduledMessages = null; @@ -256,6 +251,12 @@ await RetryHelper.ExecuteWithRetryOnTransient(async () => } } + if (continuedAsNewMessage != null) + { + await this.orchestrationProvider.AppendMessageAsync(txn, new TaskMessageItem(continuedAsNewMessage)); + sessionsToEnqueue = new List() { continuedAsNewMessage.OrchestrationInstance }; + } + await this.orchestrationProvider.CompleteMessages(txn, sessionInfo.Instance, sessionInfo.LockTokens); // When an orchestration is completed, we need to drop the session which involves 2 steps (1) Removing the row from sessions @@ -271,7 +272,8 @@ await RetryHelper.ExecuteWithRetryOnTransient(async () => // mark it as complete even if it is. So we use the work item's runtime state when 'newOrchestrationRuntimeState' is null // so that the latest state is what is stored for the session. // As part of next transaction, we are going to remove the row anyway for the session and it doesn't matter to update it to 'null'. - await this.orchestrationProvider.UpdateSessionState(txn, sessionInfo.Instance, newOrchestrationRuntimeState ?? workItem.OrchestrationRuntimeState); + var newInstance = continuedAsNewMessage != null ? continuedAsNewMessage.OrchestrationInstance : sessionInfo.Instance; + await this.orchestrationProvider.UpdateSessionState(txn, newInstance, newOrchestrationRuntimeState ?? workItem.OrchestrationRuntimeState); // We skip writing to instanceStore when orchestration reached terminal state to avoid a minor timing issue that // wait for an orchestration completes but another orchestration with the same name cannot be started immediately @@ -378,7 +380,7 @@ public Task AbandonTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkItem work public Task ReleaseTaskOrchestrationWorkItemAsync(TaskOrchestrationWorkItem workItem) { - bool isComplete = workItem.OrchestrationRuntimeState.OrchestrationStatus.IsTerminalState(); + bool isComplete = this.IsOrchestrationComplete(workItem.OrchestrationRuntimeState.OrchestrationStatus); SessionInformation sessionInfo = TryRemoveSessionInfo(workItem.InstanceId); if (sessionInfo != null) @@ -492,6 +494,11 @@ int GetDelayForFetchOrProcessException(Exception exception) return 0; } + bool IsOrchestrationComplete(OrchestrationStatus status) + { + return !(status.IsRunningOrPending() || status == OrchestrationStatus.ContinuedAsNew); + } + SessionInformation GetSessionInfo(string sessionId) { ProviderEventSource.Log.TraceMessage(sessionId, $"{nameof(GetSessionInfo)} - Getting session info"); diff --git a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs index eb3f0e7c5..4127cd75c 100644 --- a/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs +++ b/src/DurableTask.ServiceFabric/FabricOrchestrationServiceClient.cs @@ -151,10 +151,26 @@ public Task PurgeOrchestrationHistoryAsync(DateTime thresholdDateTimeUtc, Orches return this.instanceStore.PurgeOrchestrationHistoryEventsAsync(thresholdDateTimeUtc); } + /// + /// Wait till the specified time span for the latest orchestration execution to complete. + /// The service bus client implementation of this API ignores the input executionId parameter and + /// only returns if the latest execution of a given orchestration instance is completed before + /// the specified time out. Perhaps there is a good reason - for an orchestration which uses ContinueAsNew, + /// the orchestration is not really complete though one execution may have been completed (typically with + /// ContinueAsNew status), the user of this API would most likely want to return from this + /// method only if the latest execution of such an orchestration is completed instead of a given + /// iteration. Hence, we match the service fabric provider functionality to be the same. + /// + /// The instanceId of an orchestation to wait to complete. + /// Ignored and instead the latest execution of Orchestration is considered. + /// Timespan of wait. If the orchestration completes before the specified + /// time span, the API immediately returns with the state of Orchestration. Otherwise, the API + /// waits till the time span and returns the state of Orchestration at that time. + /// Cancellation token for preempting the waiting before the timeout. + /// The state of orchestration with the given instanceId if it completes before the timespace. Otherwise null. public async Task WaitForOrchestrationAsync(string instanceId, string executionId, TimeSpan timeout, CancellationToken cancellationToken) { - var instance = new OrchestrationInstance() { InstanceId = instanceId, ExecutionId = executionId }; - var state = await this.instanceStore.WaitForOrchestrationAsync(instance, timeout); + var state = await this.instanceStore.WaitForOrchestrationAsync(instanceId, timeout); return state?.State; } #endregion diff --git a/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs b/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs index 75d01e1c7..6559fec41 100644 --- a/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs +++ b/src/DurableTask.ServiceFabric/IFabricOrchestrationServiceInstanceStore.cs @@ -80,7 +80,7 @@ internal interface IFabricOrchestrationServiceInstanceStore void OnOrchestrationCompleted(OrchestrationInstance instance); - Task WaitForOrchestrationAsync(OrchestrationInstance instance, TimeSpan timeout); + Task WaitForOrchestrationAsync(string instanceId, TimeSpan timeout); Task GetLatestExecutionId(string instanceId); }