From f86a5166e8658669ffefe4c86a605489e886aa6a Mon Sep 17 00:00:00 2001 From: Denis Zhevagin Date: Fri, 7 Jan 2022 17:36:43 -0800 Subject: [PATCH 1/9] Removed hard coded Max Concurrent Items in Event Consumer. That significantly impact performance in a lot of events scenario. --- src/WorkflowCore/Services/BackgroundTasks/EventConsumer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WorkflowCore/Services/BackgroundTasks/EventConsumer.cs b/src/WorkflowCore/Services/BackgroundTasks/EventConsumer.cs index 9635df3ad..7f47d8ef8 100644 --- a/src/WorkflowCore/Services/BackgroundTasks/EventConsumer.cs +++ b/src/WorkflowCore/Services/BackgroundTasks/EventConsumer.cs @@ -17,7 +17,7 @@ internal class EventConsumer : QueueConsumer, IBackgroundTask private readonly IDistributedLockProvider _lockProvider; private readonly IDateTimeProvider _datetimeProvider; private readonly IGreyList _greylist; - protected override int MaxConcurrentItems => 2; + protected override QueueType Queue => QueueType.Event; public EventConsumer(IWorkflowRepository workflowRepository, ISubscriptionRepository subscriptionRepository, IEventRepository eventRepository, IQueueProvider queueProvider, ILoggerFactory loggerFactory, IServiceProvider serviceProvider, IWorkflowRegistry registry, IDistributedLockProvider lockProvider, WorkflowOptions options, IDateTimeProvider datetimeProvider, IGreyList greylist) From b06b690691d47222075c57ecc0f6a3394b27b781 Mon Sep 17 00:00:00 2001 From: Stuart McKenzie Date: Thu, 27 Apr 2023 14:54:17 +1000 Subject: [PATCH 2/9] add alternate constuctor arguments to allow supply of provisioned sqs and dynamo clients --- .../WorkflowCore.Providers.AWS/README.md | 12 +++++++++ .../ServiceCollectionExtensions.cs | 27 ++++++++++++++++--- .../Services/DynamoDbProvisioner.cs | 4 +-- .../Services/DynamoLockProvider.cs | 4 +-- .../Services/DynamoPersistenceProvider.cs | 4 +-- .../Services/SQSQueueProvider.cs | 4 +-- .../DynamoPersistenceProviderFixture.cs | 4 +-- 7 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/providers/WorkflowCore.Providers.AWS/README.md b/src/providers/WorkflowCore.Providers.AWS/README.md index f9c000662..0a9286f37 100644 --- a/src/providers/WorkflowCore.Providers.AWS/README.md +++ b/src/providers/WorkflowCore.Providers.AWS/README.md @@ -34,6 +34,18 @@ services.AddWorkflow(cfg => If any AWS resources do not exists, they will be automatcially created. By default, all DynamoDB tables and indexes will be provisioned with a throughput of 1, you can modify these values from the AWS console. You may also specify a prefix for the dynamo table names. +If you have a preconfigured dynamoClient, you can pass this in instead of the credentials and config +```C# +var client = new AmazonDynamoDBClient(); +var sqsClient = new AmazonSQSClient(); +services.AddWorkflow(cfg => +{ + cfg.UseAwsDynamoPersistenceWithProvisionedClient(client, "table-prefix"); + cfg.UseAwsDynamoLockingWithProvisionedClient(client, "workflow-core-locks"); + cfg.UseAwsSimpleQueueServiceWithProvisionedClient(sqsClient, "queues-prefix"); +}); +``` + ## Usage (Kinesis) diff --git a/src/providers/WorkflowCore.Providers.AWS/ServiceCollectionExtensions.cs b/src/providers/WorkflowCore.Providers.AWS/ServiceCollectionExtensions.cs index 57b6f6bc8..171860524 100644 --- a/src/providers/WorkflowCore.Providers.AWS/ServiceCollectionExtensions.cs +++ b/src/providers/WorkflowCore.Providers.AWS/ServiceCollectionExtensions.cs @@ -15,20 +15,39 @@ public static class ServiceCollectionExtensions { public static WorkflowOptions UseAwsSimpleQueueService(this WorkflowOptions options, AWSCredentials credentials, AmazonSQSConfig config, string queuesPrefix = "workflowcore") { - options.UseQueueProvider(sp => new SQSQueueProvider(credentials, config, sp.GetService(), queuesPrefix)); + options.UseQueueProvider(sp => new SQSQueueProvider(credentials, config, null, sp.GetService(), queuesPrefix)); + return options; + } + + public static WorkflowOptions UseAwsSimpleQueueServiceWithProvisionedClient(this WorkflowOptions options, AmazonSQSClient sqsClient, string queuesPrefix = "workflowcore") + { + options.UseQueueProvider(sp => new SQSQueueProvider(null, null, sqsClient, sp.GetService(), queuesPrefix)); return options; } public static WorkflowOptions UseAwsDynamoLocking(this WorkflowOptions options, AWSCredentials credentials, AmazonDynamoDBConfig config, string tableName) { - options.UseDistributedLockManager(sp => new DynamoLockProvider(credentials, config, tableName, sp.GetService(), sp.GetService())); + options.UseDistributedLockManager(sp => new DynamoLockProvider(credentials, config, null, tableName, sp.GetService(), sp.GetService())); + return options; + } + + public static WorkflowOptions UseAwsDynamoLockingWithProvisionedClient (this WorkflowOptions options, AmazonDynamoDBClient dynamoClient, string tableName) + { + options.UseDistributedLockManager(sp => new DynamoLockProvider(null, null, dynamoClient, tableName, sp.GetService(), sp.GetService())); return options; } public static WorkflowOptions UseAwsDynamoPersistence(this WorkflowOptions options, AWSCredentials credentials, AmazonDynamoDBConfig config, string tablePrefix) { - options.Services.AddTransient(sp => new DynamoDbProvisioner(credentials, config, tablePrefix, sp.GetService())); - options.UsePersistence(sp => new DynamoPersistenceProvider(credentials, config, sp.GetService(), tablePrefix, sp.GetService())); + options.Services.AddTransient(sp => new DynamoDbProvisioner(credentials, config, null, tablePrefix, sp.GetService())); + options.UsePersistence(sp => new DynamoPersistenceProvider(credentials, config, null, sp.GetService(), tablePrefix, sp.GetService())); + return options; + } + + public static WorkflowOptions UseAwsDynamoPersistenceWithProvisionedClient(this WorkflowOptions options, AmazonDynamoDBClient dynamoClient, string tablePrefix) + { + options.Services.AddTransient(sp => new DynamoDbProvisioner(null, null, dynamoClient, tablePrefix, sp.GetService())); + options.UsePersistence(sp => new DynamoPersistenceProvider(null, null, dynamoClient, sp.GetService(), tablePrefix, sp.GetService())); return options; } diff --git a/src/providers/WorkflowCore.Providers.AWS/Services/DynamoDbProvisioner.cs b/src/providers/WorkflowCore.Providers.AWS/Services/DynamoDbProvisioner.cs index 3f381c8c3..6d3c712b7 100644 --- a/src/providers/WorkflowCore.Providers.AWS/Services/DynamoDbProvisioner.cs +++ b/src/providers/WorkflowCore.Providers.AWS/Services/DynamoDbProvisioner.cs @@ -15,10 +15,10 @@ public class DynamoDbProvisioner : IDynamoDbProvisioner private readonly IAmazonDynamoDB _client; private readonly string _tablePrefix; - public DynamoDbProvisioner(AWSCredentials credentials, AmazonDynamoDBConfig config, string tablePrefix, ILoggerFactory logFactory) + public DynamoDbProvisioner(AWSCredentials credentials, AmazonDynamoDBConfig config, AmazonDynamoDBClient dynamoDBClient, string tablePrefix, ILoggerFactory logFactory) { _logger = logFactory.CreateLogger(); - _client = new AmazonDynamoDBClient(credentials, config); + _client = dynamoDBClient ?? new AmazonDynamoDBClient(credentials, config); _tablePrefix = tablePrefix; } diff --git a/src/providers/WorkflowCore.Providers.AWS/Services/DynamoLockProvider.cs b/src/providers/WorkflowCore.Providers.AWS/Services/DynamoLockProvider.cs index 6f4aca0e8..32ebe488b 100644 --- a/src/providers/WorkflowCore.Providers.AWS/Services/DynamoLockProvider.cs +++ b/src/providers/WorkflowCore.Providers.AWS/Services/DynamoLockProvider.cs @@ -25,10 +25,10 @@ public class DynamoLockProvider : IDistributedLockProvider private readonly AutoResetEvent _mutex = new AutoResetEvent(true); private readonly IDateTimeProvider _dateTimeProvider; - public DynamoLockProvider(AWSCredentials credentials, AmazonDynamoDBConfig config, string tableName, ILoggerFactory logFactory, IDateTimeProvider dateTimeProvider) + public DynamoLockProvider(AWSCredentials credentials, AmazonDynamoDBConfig config, AmazonDynamoDBClient dynamoDBClient, string tableName, ILoggerFactory logFactory, IDateTimeProvider dateTimeProvider) { _logger = logFactory.CreateLogger(); - _client = new AmazonDynamoDBClient(credentials, config); + _client = dynamoDBClient ?? new AmazonDynamoDBClient(credentials, config); _localLocks = new List(); _tableName = tableName; _nodeId = Guid.NewGuid().ToString(); diff --git a/src/providers/WorkflowCore.Providers.AWS/Services/DynamoPersistenceProvider.cs b/src/providers/WorkflowCore.Providers.AWS/Services/DynamoPersistenceProvider.cs index 09f1dbc4c..0c78c6048 100644 --- a/src/providers/WorkflowCore.Providers.AWS/Services/DynamoPersistenceProvider.cs +++ b/src/providers/WorkflowCore.Providers.AWS/Services/DynamoPersistenceProvider.cs @@ -26,10 +26,10 @@ public class DynamoPersistenceProvider : IPersistenceProvider public bool SupportsScheduledCommands => false; - public DynamoPersistenceProvider(AWSCredentials credentials, AmazonDynamoDBConfig config, IDynamoDbProvisioner provisioner, string tablePrefix, ILoggerFactory logFactory) + public DynamoPersistenceProvider(AWSCredentials credentials, AmazonDynamoDBConfig config, AmazonDynamoDBClient dynamoDBClient, IDynamoDbProvisioner provisioner, string tablePrefix, ILoggerFactory logFactory) { _logger = logFactory.CreateLogger(); - _client = new AmazonDynamoDBClient(credentials, config); + _client = dynamoDBClient ?? new AmazonDynamoDBClient(credentials, config); _tablePrefix = tablePrefix; _provisioner = provisioner; } diff --git a/src/providers/WorkflowCore.Providers.AWS/Services/SQSQueueProvider.cs b/src/providers/WorkflowCore.Providers.AWS/Services/SQSQueueProvider.cs index dd1c15e14..af2c40b20 100644 --- a/src/providers/WorkflowCore.Providers.AWS/Services/SQSQueueProvider.cs +++ b/src/providers/WorkflowCore.Providers.AWS/Services/SQSQueueProvider.cs @@ -21,10 +21,10 @@ public class SQSQueueProvider : IQueueProvider public bool IsDequeueBlocking => true; - public SQSQueueProvider(AWSCredentials credentials, AmazonSQSConfig config, ILoggerFactory logFactory, string queuesPrefix) + public SQSQueueProvider(AWSCredentials credentials, AmazonSQSConfig config, AmazonSQSClient sqsClient, ILoggerFactory logFactory, string queuesPrefix) { _logger = logFactory.CreateLogger(); - _client = new AmazonSQSClient(credentials, config); + _client = sqsClient ?? new AmazonSQSClient(credentials, config); _queuesPrefix = queuesPrefix; } diff --git a/test/WorkflowCore.Tests.DynamoDB/DynamoPersistenceProviderFixture.cs b/test/WorkflowCore.Tests.DynamoDB/DynamoPersistenceProviderFixture.cs index 6fb9c1ea9..6ec1c13b6 100644 --- a/test/WorkflowCore.Tests.DynamoDB/DynamoPersistenceProviderFixture.cs +++ b/test/WorkflowCore.Tests.DynamoDB/DynamoPersistenceProviderFixture.cs @@ -26,8 +26,8 @@ protected override IPersistenceProvider Subject if (_subject == null) { var cfg = new AmazonDynamoDBConfig { ServiceURL = DynamoDbDockerSetup.ConnectionString }; - var provisioner = new DynamoDbProvisioner(DynamoDbDockerSetup.Credentials, cfg, "unittests", new LoggerFactory()); - var client = new DynamoPersistenceProvider(DynamoDbDockerSetup.Credentials, cfg, provisioner, "unittests", new LoggerFactory()); + var provisioner = new DynamoDbProvisioner(DynamoDbDockerSetup.Credentials, cfg, null, "unittests", new LoggerFactory()); + var client = new DynamoPersistenceProvider(DynamoDbDockerSetup.Credentials, cfg, null, provisioner, "unittests", new LoggerFactory()); client.EnsureStoreExists(); _subject = client; } From 1820211a7a554509dda9f4370e21495281594e03 Mon Sep 17 00:00:00 2001 From: Peeyush Chandel <555114+cpeeyush@users.noreply.github.com> Date: Thu, 27 Apr 2023 08:42:50 +0200 Subject: [PATCH 3/9] Add performance test results under doc section --- .../performance-test-workflows-latency.png | Bin 0 -> 119222 bytes .../performance-test-workflows-per-second.png | Bin 0 -> 80363 bytes docs/performance.md | 87 ++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 docs/images/performance-test-workflows-latency.png create mode 100644 docs/images/performance-test-workflows-per-second.png create mode 100644 docs/performance.md diff --git a/docs/images/performance-test-workflows-latency.png b/docs/images/performance-test-workflows-latency.png new file mode 100644 index 0000000000000000000000000000000000000000..621fc276012896c488076675032629229042634f GIT binary patch literal 119222 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�k&`M7!Y zh#(wO-MSBZ0xiE16H`b!<%W6$%it%Vbt{1VCbxNP_k z1`>v}0s|=(pZ)33hgBywB!w})965~#Nl}R{cT)@Q(zFi zzaMbQM;6V^kBqxI=f8Th1v-umi@OXmM_2rj)%s54O7-zgfaZXD3y4U8v$}f$2mJQO zuYc@4%2@y*-CO$&u>ubL`kJSqzXI%r*v-G*pZ=}wPl3NI>{HZlGuD;(_5K_6Ujb=D z>-}HPWc|iQKQE3J4_S{}0FO}r{RrUw4zphX40yc-T=@47|NYf}CGlUI_^&JcHz)uS z_-}apf14HVWpfsNY}VKZ4!a@`(A= z4E*P_$jAnGH$V7+ zB?hCTx4FMG0<9W_e2T1h!q}_SOCQ5tw~vsz*f3f$q~tHZ)+;!VH*&7SI2cSdzZK6S z_ZRV=&(I5bGYc6RICd5z5)VqQA-Q(oU++4-dF9CvuQXsDm$6J4N^Gbm4?b{t;r*%T zfJ>3pVA^znFyTJM%b<8yUflS(ceUfoOp7Puh7w_&%Tsm*u0$jb0<9%^A`O1#1Z0y_ z(Bt~ikK&*p;Y>0(T0+KXG?H~wd$h#qff<<_HsTD&oAZaAAuwV1r5)e)31oi$K&E5& z6i1YZ4&r)OjzHqQUtKF`u;$J0OmFO*gEy-~8@EcuT}yex&+$%;=wEe>V_<<9USE~Y z=xwI8i5``X5W3xh<&F0hM;1-TK(`I{c@*U>E&hpD%uC~^3JHm62u8Z-#WZ4QJk4OJ z%bp~^1~*?^Qw0B|aYm?I92=KDw&Ji1L)^YS}@k1}xcoL%nvNOLv z`f%F@2>{RP!g27R?+*yPh@Wav6zC5{yXUN9{K;S!M?BLP+B8UaV;((ubfzDluYzWO zjodEwQLPyyypQSH(NPoPopQw>1D4`WbqcmB(;t>fkzc&<#Q-Y_X7M{m&y0s9%J0(} zUm$2LHs+z1euSOsPGvnE+j89rO|zUo4oQjT#)rVtD+E0QG6)K8plYT=4Pq-&^on?@ z+1RS)lIBxiN8qTv^qdc&9$w|-uk9je8U!-~p*`3_nJOgRgv^=TwuKGT-})w)MKyYq zvnQsGiD}{LX>&S;3QK>CS=w9hKP_s-7+}ViVLnwwR{mWQR>AUn#yvjs+*enuDtl}A zUW}$ZYFVs3B=|LUoD3qTIne7tKd{CCD769b=OF_yED-mIsbv(65%nX8d2sPJ?2t*_ zsD8iI+l^L715>mx!kChK8GCb1@P9bGp)X{V3`F&7$)r~C0#xm!(=*bv;2oW`2zr+@CJcz@!+ zHGM<9{G5#RTl-1sb1??lLd(_&CuBu6xAe+{D*s!gkEpwFA-meI)l=F*@z-OQ$WElC z4l3%`*s!|S%YM;$EhR=9E+?KH|>}ai|0D?S!_qf!NW~Q zI=h4Pign%Zr?6p_o!PWf(ML3kAriK8;T3fwvd|Yg)yOCDvsGL<)at>|=?Zqe+PP-8 z>R?=%qj~iH84~`CHFi7eQ$=Uj3MVc=m1Af%f<3G3j0un6bk5gdE!f8B>=Y90Mv>Zt z5$FY^G0h_6z5tLOTIVdHMXrk#fZS1gImtgHEzK7;4Ayu(LIo!Y#fI-U%hW z0~fgr3lg1pQtF0Qrt2n?!-2itn49HOVSK5(Bz#B7;QaIuvUcb@?E={RO!}!{*46n0 zJfjJIJM)G6<(B@4v*I(u?3Rph(cRFy%O%Z6pT4)_>~85{Pmc!%A6(g3^;!0S5Y;$5 z`nV*%n8t`KWU}Sle77~a&_DSgND+cp7meFc;7wAC@k(PGh(G>hoki zW@FR49ng)Pg?Z^v1*+S9^dLU`RbDAJ$`3JYW&~aws(^@+r04>V4}oCv<{ywVD@LQ+ z*YrlOD)^GyKaNigG4?HbMzGj>V?{&iswtOsrsjnxMOwYsd=iQD+C}i}Y4wY-Ez(hV zcl->F>$9aYSP(I<)?X{J10L!BCWF%=;0n7$(uY-3Un}hkYUGb>8ItVcv!%4>cB$SMr@7fgfRH!-&&kO?HYmBzcVkYUO zPKR;tzQ}_Fih$iC^e@3qz`qdt8L=iFx7DeK!J^$R6^Hq4EV|HXb=u;Ffung_W48yE zw-LWOa42ra5?`%JZFye{82N3MHDNw95MFz2iLSFun7WpOKz2z#og<5n4&5 zZXL-%L7Z-eitl?}EU$)HE&L;9_NRYs&XSU(>RM!CvDyStn;%qV^+7W=xbEuL?{-gB zPiF%w1*HZ)=j-(SPuUHFfl*=WC8uS_hP7dHl2ynNfBKT}YjO^TvC)v1atAq-&>`;t zLUe(Y$Ay3N-tGpvaLVIq2ipg{$|BbSk#=3tFqgsJNU4jLeAMK0o360pZN8qi;me8Y z%sDbxE-2A{^w(cuX1QjO2ESmW*hMa7LT+wE(kS+U@<(Hv=zj6ajfS_>ba+1Y({RHvIQS`B~KwFyxp_9OX7`KK3LkZ_uip{adR3N0WC zyU2x=pV$@4vzzi+g>K$^8R~-e0hIa!~Z35;Md3(2dAPTP4m zLkz>i64$<>`l*n&=Tf&SEf%b(XAV9pUBeF?iZ({gc@#7T&Jgj#8IkX+PPxliT4lXt zez%+fT*SZ6`ooHAKqU=V1k6}O4^79PVwXPGR{s*IUs$7k^V5yr0zEz5gW3PvgbLVK znzgk?-Z!Et2}Oo-c)|7@Uln1%#Rf4haa0CmqH)MLQ-{)Bi{3j{xNMU=+1gUA?UM!7MvG{8}Tq|&3j+?KTkXxwMMVE8=LakVa+CA7; zg_8G`1Y-o}9e**TTaZ@zZeZ~WssI*=+ZZ2$7mV~sPlyYrA9fVYE2E@D&Kb)b(@f_I zq|I8Ryk^AEHi68ooj^p+*={6laYJMOWfRd68`-JM23Zlem08^vcqz`R19Hij{V?jg zCh};XofYBN@w7&<hE1A7cBi#uitT3#L}DYP()1`$0#=*S=58TQY_`DlaP& z2Gtkd8(YRnbnNARcl#_~UalyTohmPhhsR6Zyk#Yjfj$e3a*O|#=E4R>N*nHtpX{$yLyTb(1S$6n-B0J~E) zSK0l4k|bmNtW)2`81>Xx&b{+$t)af?wcYwN3mevfk#Vc)-1bqD3;MM0KS{ycL7KaS zW4oLhxM`OjiX);7T{@kj><*7s8=NlTI9xZeSM!(tI!vO{ob^wrgZcU2XTZzD5hrx} zH$Pq~#Kt<*%j`z`?ANOCD2!LRq~x$`c)z82-5mWrL{?EOMDXkmFqU=8-*RMX&E@gq zOND4w2nCuxKxI%+N12jC<9R@1*6b+~U9F$!H9&j-E=5K3_h(tO55o7zg}j1}+^jNo z*g_BY(J9OCXk(&e5?1c7T~h%p6l^mp8o9}V@kv-L_Hem_wqshk-<;y#jbd7D&d2qN znM!F8zYR4-Q9f3o#>Li!Mh>`LHQa=f{Qv|b;TMxLLrc6;?tunl$XA*#lp^jMBQ5Q~ zcJw*5Mtg(hVM|t*sS6B$WVJip$gJ%jHQYCj7FMnYc>&Q&Zq<3cQX*fBqJXC$ke zQDN}_EDYf_65mH4$bqI`85M6;@>O2k4f94!z{|od~DrPDXLpGb0ewfei_KP1kn} zo6xb^W;{G*E`ZJD>Jl^ zkM*)ANA;m{YuFC~k2xN%rPXOp@0O91HB=jApm4LFSc$kEXR(VNe zR?Ek1?V=ePV@+aL6kmHqi&}j8j?6|SbNH_~vnFxi_o}mo&ck{}iK$J|tmud$$|J~B zkfUe&CKip{cA;L+Zww+k1n8k+$}vc$Il3~^=90e=jR%rP*)c;fpq{S;^%r{gp}xOW8#?0I5GI^@0$%=5 zSU0m)Gv?LW9}f6r={~v2T6r4LrBd>OTcQu~{N>bw!RVFFy$m5la!a<`&b2S(Vyzu!nRg;+ej@l;wD*Ad+9-lb1|H};a~*bRRF^7*bbCHs;jUq_{u zfqlX)v=gf;OAa!2UX|>Q1AY)-Wy)t^9*aDvPZ!2u0z-|>!A0KRvMHsFVwJ0A4B@gW z{#ppx<})*g`tS&D5w79H9F#!}3S_|9v`khToHSSbB|dL#OGF#KMv;d4#vEJ0T0MKw zatQzGjS*YO&SFL`Z4Q+Xg#RCA?vgrZ>LxeEc<_1w=G1v z!@w`%^7DOd8pGZ|Ay)yz@gnzv*X~*wJxV4=MDQlP%i|XM`#%^X;?yT4T?~C|B(HZk zDLebeGx(tW9mITMZwewBA8-SjFI$hQM!>dkmm(|T!B;A*p?ez!Hgq;16Okgv4{TdilG zvGQt@s1b3{ywYfhuoPc(!Nn4<$=l&Yfq|A=GJs4i=?aO@I(=4K@=I$roViH{kNS8i z=cA{4-dwHK7X&>@rIe$(sr8g=kt9+xLH!|%WSj(N&E*-b<=4+&3a+anv^iBFpR}{&7yKGaxcf<@6jozK2s2r{ zxu!>8->ds}===XrHmatxy*HX(=htf`I36w9vNGdQIp!w-6UpDFoAJZUyal^ngz$z) z8U5x&>Z?vl$0gka(WLe4Y^JR~;kr_>70TA8PD#%=$8uBi6y;L;zAB|CJ#S0_SuGhn zY0VHjb@Q!H!Sw)9i@cRZ$CMEL9z+Ig=N)l42(SK=rPvZL~vN)_TBTOP&@- zQAT}>2kB{D)A@C8K8_9wu1}Irl*~u!<}cNc$hq)6iyDKVr!%|j(G;i*d*5Gc)Pd={ zjkr-?xinr}f@KjSxnZ+%Mo(L7BQwUyix5% z+{+bcO56ss#Eg&CTpP1uv|{k~lP1~M354zTO1zkMvV4W;CH znk2ngrm1Hj}s3Up`0q3>1x{_(i3%6Y*!rnSQ(8mXAl1>Jb|UI(5>|CXZ4I z+Dp#PPrYJirtdq6%?D#zVQ2qQ5Ws8FR@VLrU?YS|y-!-Jp-$MaCrTtC>SR&WQmWV9 zNyz4z$!N5Xrhl@5AdJgyriKa90#I4{s_oW3d5jIVMQb>EJEF+ok;7OuXUTclzn0?g zcF=jr2oG!<5SaEp)7SbIDEIC=7JYjO+qpfFadca!jH3A!4Sx<&YEXB}=lTlI8} zFh=y}%B*($-b6k~I`lpG(aFpl-s24W?c70VV~e}bC1s1X&0X1|Gx)Os5w2CRF}J(# zTsp>~4?HcF>7QzLBHO(QQ;rpnuf`ANNp{tuDVX||a6C>ksd&UK5eQMAk?$ktJAQ2E ztAa-^Oi`nceG%>h7d|?DnDGKA5DuO7lV8T(;@0EZ@!PSX%uTYW)w>0VAittWbY?ua zkRQ7{?-g`jra{=4?ekhH{?Uu|+=1lr|ASH=kab=27N5OjRxY)FyP0tq&!g{ruyBTv zkt=VFN9oD}TifKCW%|yk*0PGQZAqYxV+xR{@rWk*p=Y31 zA2erpXzq`n?Bf4h5dlbi)lt>k@B5607TM3;EUEkWWLpD#AHiCV_B6%NFh=GNVfc;y z6?|Oi_#L?g7FyNug7>ql3Tu?b=&nu8dFex~#qRg(fK*|ln0l=3;g4kd^2ansOVsPZ z_Zoo?>VYpEax*ut3N53QlQHk8(K`jKWh=C)=Bk7S>j~H>=UnC$+k=Xlms7CwaS zsTGgODD3lYIWBjH`Fb>M$>sNsB-o4_+YGT$wd|59|7U~Pvw7Q6#J1Bt19^Ss2k$p| z!BBU9;s=4`0IZ+WiTi0?YW$RIGiB=r=;VA|7r%LZIzW?nXPs^FNQmX3)*??VU(XQ_}%}by6tWFO6a0F zs_BEX7yaq58!rzmUmwVqYU;d_l^KLJ_cEQgsEP>c{Yrj8&~uQq(_eC<*ZmFtwvR@9 z;BlXcH~AdmGLyJvdJw-@nB)I>HJK=%<^$}2&t7&YJ8nauCfV6?d?wX%Ow$^+au0QY z2|p*7#y(gGAQn{;7fdCfX36Z%crii?CM~origGgHy;5)W8o_eQ9F+Zx+o%T}Z@OAp%Tp=J3)sbjUl05iNJ&m#Q; zF$rv5I&!9Z0KQg@+%9!=@R#xX-QLJt$_pHPhfivM6T4Q1HQsx6>EV<>tAF&Ka{GDN zb+QGC7w-KBr%Ik~>3U>bT;Oo&!u&l!$4d4!m0DGA%a=7+@mrw<){83rFY>O9)~&!? zbZ(2&q%eX;uoGl8S~-atgTWsZ}# zb=wu^$*U{Q5rb7CQ(5immjkwhm(r55;fu@txlwUN@OMdH1Sdp!ItO}X|n6zI!I@qgnBi}D+Wj@Ib%);IYdpjFr z0K`5FZ@?hB_t8QcoG4rZ_;g49(>+zi;cr%7I;>vt6SMC>HyppR`5rz>dF}*?#L>Rt zcH|#khdG2kzwUP38(SLUE=?MZa^4%4G{u<}{VacDd=AB)aou9?6#9BmE0)J@_Hq$T zJHMNAc{~nz0-+Zevp?{(msGS3Juj(66*}ifW`LEt^%WJ-_%V_D6LEt&Cun-xYwlUnagn;ixR$NvquRSX{`}Q| z`zn55*Fy9>M|Ojk)m-ILn~p zxA@UWof7#E1PgjW$#o)N_P1gxvD{ls6356bIEoj!H)clhGpn>M4(AkYV<2QDkD zoB!8eA6CTY36=zfq$4}P(p5U*2QLl`>7*+!o*GRZG0X~l2FM)HuH}Qp;=z5!bRW^3 zP`nu&*yo*3kW3>YqxF%ng0=pUZyrj=nuME_@%7F0pX3F0*=IULzWnS^@I{r&8@2)K zApgQtx3Q!9KNqVX0}qq_P(aosru;}b6gtcrxNzgGy`2mvt;?+7OZ}hm?)~*w#%2eu zpZX?^x6A1ee#$}(;I6RY3b{;^d73Fy=3w3i+mVV-HXLfJ_RU*xpj_%4u}pn`vnKN8 z3hey}uy_eQmgmw+XXPm?fMmiK%ekN`a@M&XL9di>YyI?^5U4l6<4~P%kO~66a>cpW z6&Dy^Z8$xO*VD9G0jgf)-v}%8YFgj-$ScfE`3_)?$fYPDnUq-w-jXuKG&@X=CJ818 zp)NAN_@TOLX;|WNcWz;!(!p)nx61+41H+3-x(#?9r~|N&4az8;I*XV5+js-EZ*t?h z@J%@|EB_dq0ID8?1Ul0)EvknjwS-97$Aqbz-(xmga(+TH?A zYW++6CVq2@l9k(eGR2H3u`h>N-JU=6wDjI8>ln@%e_iTMOmwVjL83PSHL*K)9^Ev4 zi|ucK!-?y;O_XBFfnWpKqvLU(zD#j!-oyfsXPWK9WZP6dY?Cq&YeK&(xWLpo$<+M6 zLib|^@cAyr=qt58Ug!@l$Z;ciecPO+TcR=p;g)hDxNEJYM!qYY<;w#p(akF|rAiRk zA@*{CD?`$&MSX^g1z-k{5y=q@J6e>X z^W*l_8aBZ@FvYtS`D$!Sh!gk^L}QTkl0jr{gm4bOP{V&f@}Y84ai7l}D5zSegy!U$ z^VV~&x5Q~OsG~c3>D2dtfUlx@d*jgQ2C#I{3?g=@CykdYE-sXOp_5rX(OrWMMj@|q za`!OK@8>#{Pdg2%7d)`-EChQGvO5|(Y>b%0^f{3pBd)>{Qv}pi913S&NDJ0f)=lqWjr-JPhjLX6unhe+dU0 zZWkYpj^ONnNGOCxPOZA@j4@+(S|0Em6`3ahq~t(q30GjzSjgxTT1NbB`Z3dpX$(K1 z;Rv*PDlp46Gc;6gErWipO&w&=i!*&)*A2P7#-<*HmvhRT9`~9W()r+Y*OH;UA*1#U`2MdV*n)XZS5_C4Co=F7t zZo7YS(y%<>CLWMCh|B-dS{%dk5Eq(VlXcj&hSsmO)No$Ubh}6PP?P#TJDz=fzaosl z2HmFOB=U}u?C}b@r&>y3!&21cmc*Hn0iW0C@I7)bPF8wex!s!(c|IHxT^zUL%Cg$a zt1cVJzA-T7SQkcrMk?N+&X{SAG9mBS=6}!!xq2GXbz<%QAf52%??#;W!|I3N&DwJp zmO?AmCSVE!^(wIx^41CMDX2_nH5rr%htlf%WjFvA-5~7xSyQHl;)@Z>8v3hsqNq-s zD$NHD!wAP?BUo^A0c$GmE9j7gL2y>@_X;OYvEHo9yRew z@l>c+X2+k6TXY)QRg!Q>o@PL$#ZSQMd8#qM{tGx=*etXR@@y)Bi$X2u!$TI8I&~tP zvyhs%mY?|RDrVHxQz+OdBiXlO>?8O}x|YoF_KLyd0bl-8&=#D@dc|=C!Tb-|0!FGq zs$n305`M1Qlac39Fi2K=T>sxiWfwluqb3k3;vWcE#VV6mVIk6WCBC#eljyOVZ(+fq z-&>Zh?%!p1SX$|5&RH2dIovb?W)0?HQMDP5UeOq4g2z;1zb-JyW zwhw3BGw>nloU-@l?Q62$@@DeZ0)xiz9WJm@fEyLv7PSmXWFhA_>x}jCX|uyJD>M`T zsvaB_7pA6gEO)f~;z)Y$-EnjvecCV|kUwlv*5n1VMKb*HhLQg*f6C&Jf*ouo=x;b= ze;aWD=S#<)C1Mg~(97qt4UU1WRq9*zoXJ0xHZyN=DgQva#<2jYtJ;!m?u>u(t;UM8 z&{yzp3U1n#XT)}$lD4^_)%zhsV4GV|?LI#+bN0PJ27@nLmUPSAhuL)YJQ#jEgQI4*!@SSukt93ej>Hv0<8AH@2?q0f5l(g*e=(i!f_DCJTzq&HW zr9lo4oFOhFE*YJfVH&Ux9?{@l=;fDw*Yxku805ap>nro%?cMPWN1j6heF-{n0L<6xTsBVWu4OUQ=n4v$%-1SHaCB&ME9e|@H>cQQAT`y)oOE^Z9(<-mxp zgf)4zI1tWOKM1p6CvSRVM+Myc+nrSN1{IAW+A6Agy~oy|QM5$yGTVwVoci zAW1LsL)T3M`bo&E^&9VlsRbS#%FlsFqw^&;Ufx|bW#WC?`o|qxhVgfbN%HA^HzLc+ z4am3A+;IMZ? zzI_rGb3=e}0kVxZaIfY*xJvw(DJ|}5=5aebo}FzMylfre&aQlJ4^0b&UVaViI|AA5 zLIpf&WMR@$+P7CMVFeZyc^RyuDAM;L$BY3HhN3rgThmm2RwE&@0QT{}s6qN3SI{X25jQH|alG&b>WT+i873*rqgO*_B5`Wt09{}@bmQnm z+yqFJn!x8?Q%*Ua$+N!@(YX~}xpV>C==MpqM-+RvmnM0vbz748-rsii?xsQXb!eui zt$H4ike#U&CvUPZg@u0xxK35vhd16yoMw2cc)EkNDcL zBooG#pb!6ay3>Lr!;6ZZR#n|&Ht3XKUMCf})OWfuu%a5OSI}*Ow#3LvE8FJl^sNcb z=(N!}vw!W}(@fL?n{ClM^{W-^rdhu*{b|MWN0|#hCg%0v-=a&|TY3*$+(37VUJs@u z;y_wo6Q$QP_|{#gjredJ6tblMJ~F{~h6FP$4`FdnlDA$(6afuJbs(-oL@neRnEU`N zy}f=>C1k-$0e_?*;5_ec0KQKWDT#V;DSnMaZ1_-#Mz$G*`y?#7Pj75=-EihVXvVuc ztSNua%FqM`_|<+6?bX4X`kBYpj(LTqOvq^~>*xPb|J-n`wd-#igBkq=n^tg8s=s6B z>dpee88i8`{;N-x37Z5rDP4ViWW$RvANTF+fxRGODra|KBN-SEd0HL;EaHCIiU~M%VZ(qz9K$|j?^7h2%U|wSJBwcf7zKQ-KY_6LVdyuDI;gpOFdbe z=?~j45c79Y=iOXaLODP{n`G1dEwHBSqmeG0t*1)PS2&zxZfH^HjgQTP8m9}fKr`>s zJo*8cr=WM>=r-%EuoB^;*p)kIkJ z{4L*Ou=P)1$M;_jVemyOo~$2es;CVWm@%H;sk-9V*XtQCza_*#g^N$#Zhv{5g>-fC;tIm8(8Bl zltRIDt>2uBe0lVRQ&-Wt;~&FuAIs12WKSbE@(-S-$#B0@s1A~Oz_*qw^g!a&bzM@6 zrvI!&-R4{Ei+PFKZc{x(hs6vm_D0d!^J$+QpmzMUqFqH@u5PGR7l=|`AhOo-c5)#e zy;mZX^aXFSLSI?y-0&D!eEeUkgX%&rb+;x(oK|K=ZCNuq`6tF7VHXYF?GF9Ant$H8 zNn1`I2nFEQ_}Y-QQ+DTg#s{?5%su?e2Ctc-cSP7Fe~-tQ@6d`mFsr0lI1q>QlJ$Q5 zU|O?z9iVs)bPKH#65rPXZrW7I*GK_1jLu(1;h)Z_KM!BjcC)?EG5C6rwN%6irR;1= z^DJKtWMU||$AX36(q*ZY1;RC*g1h4Lu#6jijco7XmZ9ZcRC3g6Y#%KMe}IgfifY>- zzU`kWH|$9syahEB5$iA*4OW>j9J>x|maHDDy%hfme2l(Yj+yF2Hz8J<^j%1EoY6QF zjx$>MR>KT#_47wPb=gavy>FV{oeZ~X(P3iu^YnV0`d)FTY+5oZ#0=9DA??Vn}`L7LvI}`xt3Xy75slZP)~P zV#-PmX1=Z!XCy)ZG@&%hl+VY3$%-tG%Wy{>a)q8bwOTru@bSQEXn<43^LuqnPjYt<*X zLL&6?ji67e0pve)MP)_GmGev|{Q2Ah(0YMb=`(|5DH|T>5?ao_NhdLdQy7eY-=A_1 zeMUgn6>!o1oio63B^n%66N;Ymi&S?yZ#c7LN~PAfrw2smUf-j#u3rNYP^D?$gyNQ>5BE!kzRs$73_(75WKUSM^PrDJs9k#3*aa?(HMSk7W*sam) z5L?N8S%vRXhL>EPr!7zSS{EA2HG9KGYq1{pACh-;`(sAi<(b6jh5CUaeX^_W4(y$- z^ly*uH*k%{Wwgnxl5~56DLBiu#)eTc_{tohYPIJcDuM6?d4h&e=A~}0imB88^j#V^ zU(q#JHGCbzhk8|f z>?8r>EE?&c^Hm!BL(zuLvRtFN=aKEh>Xy8k<`t#uhVx@Y2Zyw-6;yDY3>smvQWV$G z>i?iI>IY7QB#kjq=9Eg$4b8t+3jX1BB3t%OgQ)F8OLB)WF0wllJ8BAyw^yy;lqD5D ze|5L}*6wg!FrbhgrCv1qe$PdGl~nhh;&cbJs%-&Tew5PgQ$31vAZ|#?(o%I+*uk@Gy?e&SqxcZ5)0=OZ`Qc%#qM3)I$wud>|Hj>w2e9OPm)&2hVE`D zUGPMB_qF@07Qc762CzU2n1Jv5kWnJkMgMZ0Xvh$@FmMuzO%gCv;$E=F`NK8BJ9$Xn zlG3B!vw<|(Tl`%Jj(uF`UY_aN#gTQ}Of)`|%K8PgTlo<>g5x9i)gmJ5yscwR_ ztA_JUTyt@1#0n?YA|L%WGOrM8L^5$Qg?(obT1Pmf%#k@#yWWA&9ZKXYD*EB^L(dv&iuZgnbiR>X8ACi3 z0oLCsU>Ccd_B^o4acJFHo8h@f_l`*M`#q|o7aJzTg?wD(p06~^2s`O_kFWxxtwl^a zg|rzSdhSHZ!9n~QFOTAtBegH~#Q*pz=YgR3c-$R!ioj(R zUQ~D1L|60hfXxC^JwPmOFRxz#v5Yz@YbzXudLg z4{UTnPBB75auY{vtGb^Np^d}Z>SXxb)m}TPrCL}Yr*E+mXF2f4KUu=y)9S`R&;vt+{(hw+mp%CmewnqAEY4;P=^pf3s`s!8r9zeO@=Qz}bYl z-t3!2#WX#R4?hXH(g{6ggLm(&=|==q0B<7Eu`5=#!w4eswLKzqaWEY-r@r`?z8Ig^ z$KT(TCKkJHa~I6#=X^dbU+2I@chQ^w9;x9DMa@}lK{)Hp2%**|CFaO{5=5g4ah;s; z{+-qSF1D-=fzf$qEKR&Y@bwRq85#dHUw&*wWaQ3-f74U$TqjF#hJ9CMzFzME4f2+X z>`%uyFBgrFa^kv(XTsWhCJy0d7;1kF^Tt4LqFnyb!5uSvlRS;gsZI6pa@INq3_~mw z))8}>oqU$bWoj`*%hOn}?JUJ3Tm0qR)g@V1WSBfS72gb<)_b(>dySi4Ft0JJgSOYm zJ#(&6-_DDV&4SY@&E&fZLEez(s=0F3PR-PCju8CMUItRI6Rp;XYpudo*%!H%L|W6g zR~!-Mg?`M&xnIpGtULA16_Ta04|(+59D>rdHmSyaj-($8^A*OX;cCP;8~}1(8PM|X z58@6dK933Z$^p!pK&01~8a75Pc zCCy}4yHJ$q7^)AeUPa#;HtPJ&F|ilo4XG$vY}fJMtlyglx9&}KE}|0^c7j!470k;t z$r+3n$RiwCJ3^4^W=<#(%ewc$z;w&m$pVD`nq(V;gmX2u9PF!ic@=lfheC{tO$63& zJ6lc4XCyomM>|!rU3!-f6|KNH?U_U=#EimNFf3vwN%VK;UyzdTM>&bQg%~c&&qx{r zL0tHyZvv#!1_kpS8{gV?irWSB${jHg3xfH@2r^0!Ygv)9B#-v-X0JwT?AQK z#H#&aRg6|301Iq$hAxAYubi%zfGUBr_8ZC#MPs&dQ)AC8nM7z>7ZUMxNe{*V8HWhV zti#FvXc(#!84RZT@%oGI=WX2k{9pvBK7hkG(B(H!PxMX2`0>JFL~~9nDz5JH594ZL zURQ~q{X@>YKnhGRGwSR*eT=ZAUz=vB46qO3$&GGbj5vNy;#;hV=~axH`K~YmwX;#1 z(^;dGJUdg3gqs06h<{O==B>0N4*v;`EgHKj@uPOcxLOh__-MW|GNMY3$~E_?j7a=^ z(O=K#OQbg6PNvz@WN15u%8%~%R(M#lG8xl1MmL`9Vg~+*T^o0)Y2NzNnLwNu2;i%= zy;E_!6rgJ#?|=P$v;^3q|L@tp|8LLs0V4nJ$;991Z~iNZ|2p6Q|6D=r*X5^QuLL?+ uXub-Zj{5a7<;IB);MRXWdtb=Hi_pRCUXznB=H#zmUNW`1P<;N@-~Sg4KhHb> literal 0 HcmV?d00001 diff --git a/docs/images/performance-test-workflows-per-second.png b/docs/images/performance-test-workflows-per-second.png new file mode 100644 index 0000000000000000000000000000000000000000..8c4b61754bd45321b3768bf362ebffa4aa5f9e17 GIT binary patch literal 80363 zcmeFa2~<;8*D#E&)>=ihT2WL|Y%R7{(3U}Dh>D8V3TjnEkT@eUMCKtR*QY8_sf3m) zRfJTrqB5iyAPgbVq5@)w7y%(95yA{f3?T^_Ztj1A)>bVf>s`8BL2fGJ3!J{dd7P4XSrE;GYR$+uhb0<<~9f z1%FKRTeD@2kx>D0s%HNr@Z0-azumF^>C>l8O-;?s%`Gi0;Quc^US3|lzP<+!9`yJ3 z4-O7Kp63=878V^HjlbnZ0H0gC2$Ve##S^0J{!fwDe~R~hU%co0V(;&%z9&zfOiWBX zQxb3%e5k%>%Y%uf`+j1C{tP~}gTK%Z|HAP9<-ALPIvc~r$Y(u$sFWb`x%sYUmq02~9G%Hw_B0ssDBtNZ@zfcK4z{_ty@VPv$Am1|*SbUV|_ z74&wd04gxT9WkC@WF&uRrt5Iw|LG35bA4zl9UL5l=p|~U=pOr;e?Pq2Ar|3_3e z*26s$5}}QrMK#Vi;pM>ja_$y3v~@^yUF~U?Y;A|)A@iRyMA*&{WP%X`VD{mI3h#UU zBFs}&newUGS8kveZnvwEwkO8XU8`-d_4BY}ku(G7GD#L3dLs><{9P+`XCPD&6$#&! zn_ie2@cwOQuvt)eYh9`(JlWp2(8FG=A_mj2Bo`6-*LHedyO*Nh+T~J41r!-hkNNW- zb6m&UUUfLeKNYf>nlZaERfIv{-ZoM57ld$z<|cCeuvB9W_X*|)@9A&MS=N~1a4X)Z zwbJaJ=YHIN6Q(F_&0f5);eM+2ho#)uTk5*A^#J5DkK_Frl7F`4tU$g)>Ko;yyA&rM zk~5<$FS-mec7ce)zK;qv$q>v@sOeC2V3 z9#k*G@fE0|vUyUjTuFw*@}!~*Tx=6gKG??`*dpy1l0VaA!M{glMN?s~#47Gwq<@zr z%R8urJO#&rA0!LaJI@4EXOO7s|5y^Sa7k*D@H;A_Bo`L#bMpkN5|xKVWb%u=1CfI* zn2MD`yWh`NWi#MMRm=sD%=!Msu3n*n^Glef%Okr~Z6emhg+&y0Nz@#_`9q3uZCAaV ze>799%~Q~Q@Pk>N>8ai?x57iQ42Ky)6_!!s<2ZDAftneHF7g<7n8^>`&{daZ0$Ycd zZITTQwjWjm%;)ZaYj=gvGcIvFcLyIC;K|`HPTO{vkQ6w@-Mo1f=_)LKadVUWf_9lz zHx~Qe(Ag$#Dx=@M;6eibj7F{T%y{%9=?ZimsX)QY0j6!Dw2%VxH4t�(Dl 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 literal 0 HcmV?d00001 diff --git a/docs/performance.md b/docs/performance.md new file mode 100644 index 000000000..77fa625a6 --- /dev/null +++ b/docs/performance.md @@ -0,0 +1,87 @@ +# Performance Test + +Workflow-core version 3.7.0 was put under test to evaluate its performance. The setup used was single node with the default MemoryPersistenceProvider persistence provider. + +## Methodology + +- Test Environment - Test were run on following two environments one after the other to see how workflow-core performance with a lower vs higher hardware configuration. + - Lower configuration + - Cores: 8 vCPU ([Standard_D8s_v3](https://learn.microsoft.com/azure/virtual-machines/dv3-dsv3-series)) + - RAM: 32 GB + - OS: Linux Ubuntu 20.04 + - dotNet 6 + - Higher configuration + - Cores: 32 vCPU ([Standard_D32as_v4](https://learn.microsoft.com/azure/virtual-machines/dav4-dasv4-series)) + - RAM: 128 GB + - OS: Linux Ubuntu 20.04 + - dotNet 6 +- Test Workflow: Workflow consist of 3 basic steps. These 3 simple steps were chosen to test the performance of the workflow engine with minimal yet sufficient complexity and to avoid any external dependencies. + - Step1 : Generate a [random number](https://learn.microsoft.com/dotnet/api/system.random?view=net-6.0) between 1 to 10 and print it on standard output. + - Step2 : [Conditional step](https://github.com/danielgerlag/workflow-core/blob/master/docs/control-structures.md) + - Step 2.1: If value generate in step1 is > 5 then print it on standard output. + - Step 2.2: If value generate in step1 is <= 5 then print it on standard output. + - Step3: Prints a good bye message on standard output. +- Test tools: + - [NBomber](https://nbomber.com/docs/getting-started/overview/) was used as performance testing framework with C# console app as base. + +- Test scenarios: + - Each type of test run executed for 20 minutes. + - NBomber Load Simulation of type [KeepConstant](https://nbomber.com/docs/using-nbomber/basic-api/load-simulation#keep-constant) copies was used. This type of simulation keep a constant amount of Scenario copies(instances) for a specific period. + - Concurrent copies [1,2,3,4,5,6,7,8,10,12,14,16,32,64,128,256,512,1024] were tested. + - For example if we take Concurrent copies=4 and Duration=20 minutes this means that NBomber will ensure that we have 4 instance of Test Workflow running in parallel for 20 minutes. + +## Results + +- Workflow per seconds - Below tables shows how many workflows we are able to execute per second on two different environment with increasing number of concurrent copies. + +| **Concurrent Copies** | **8 vCPU** | **32 vCPU** | +| :-------------------: | :--------: | :---------: | +| **1** | 300.6 | 504.7 | +| **2** | 310.3 | 513.1 | +| **3** | 309.6 | 519.3 | +| **4** | 314.7 | 521.3 | +| **5** | 312.4 | 519.0 | +| **6** | 314.7 | 517.7 | +| **7** | 318.9 | 516.7 | +| **8** | 318.4 | 517.5 | +| **10** | 322.6 | 517.1 | +| **12** | 319.7 | 517.6 | +| **14** | 322.4 | 518.1 | +| **16** | 327.0 | 515.5 | +| **32** | 327.7 | 515.8 | +| **64** | 330.7 | 523.7 | +| **128** | 332.8 | 526.9 | +| **256** | 332.8 | 529.1 | +| **512** | 332.8 | 529.1 | +| **1024** | 341.3 | 529.1 | + +![Workflows Per Second](./images/performance-test-workflows-per-second.png) + +- Latency - Shows Mean, P99 and P50 latency in milliseconds on two different environment with increasing number of concurrent copies. + +| **Concurrent Copies** | **Mean 8 vCPU** | **Mean 32 vCPU** | **P.99 8 vCPU** | **P.99 32 vCPU** | **P.50 8 vCPU** | **P.50 32 vCPU** | +| :-------------------: | :-------------: | :--------------: | :-------------: | :--------------: | :-------------: | :--------------: | +| **1** | 3.32 | 1.98 | 12.67 | 2.49 | 3.13 | 1.85 | +| **2** | 6.43 | 3.89 | 19.96 | 5.67 | 6.17 | 3.65 | +| **3** | 9.67 | 5.77 | 24.96 | 8.2 | 9.14 | 5.46 | +| **4** | 12.7 | 7.76 | 27.44 | 13.57 | 12.02 | 7.22 | +| **5** | 15.99 | 9.63 | 34.59 | 41.89 | 15.14 | 9.08 | +| **6** | 19.05 | 11.58 | 38.69 | 45.92 | 18.02 | 10.93 | +| **7** | 21.94 | 13.54 | 42.18 | 48.9 | 20.72 | 12.66 | +| **8** | 25.11 | 15.45 | 44.35 | 51.04 | 23.92 | 14.54 | +| **10** | 30.98 | 19.33 | 52.29 | 56.64 | 29.31 | 18.21 | +| **12** | 37.52 | 23.18 | 59.2 | 63.33 | 35.42 | 21.82 | +| **14** | 43.44 | 27.01 | 67.33 | 67.58 | 41.28 | 25.55 | +| **16** | 48.93 | 31.03 | 72.06 | 72.77 | 46.11 | 28.93 | +| **32** | 97.65 | 62.03 | 130.05 | 104.96 | 94.91 | 58.02 | +| **64** | 193.53 | 122.24 | 235.14 | 168.45 | 191.49 | 115.26 | +| **128** | 384.63 | 243.74 | 449.79 | 294.65 | 379.65 | 236.67 | +| **256** | 769.13 | 486.82 | 834.07 | 561.66 | 766.46 | 498.22 | +| **512** | 1538.29 | 968.02 | 1725.44 | 1052.67 | 1542.14 | 962.05 | +| **1024** | 2999.36 | 1935.32 | 3219.46 | 2072.57 | 3086.34 | 1935.36 | + +![Latency](./images/performance-test-workflows-latency.png) + +## References + +- [NBomber](https://nbomber.com/docs/getting-started/overview/) From 406f4869527d95d8f6ff1cdfd61befc53f038b93 Mon Sep 17 00:00:00 2001 From: Stuart McKenzie Date: Fri, 28 Apr 2023 11:30:47 +1000 Subject: [PATCH 4/9] remove nulls from constructors and dry up the service extensions --- .../ServiceCollectionExtensions.cs | 37 ++++++++++++------- .../Services/DynamoDbProvisioner.cs | 4 +- .../Services/DynamoLockProvider.cs | 4 +- .../Services/DynamoPersistenceProvider.cs | 4 +- .../Services/KinesisProvider.cs | 4 +- .../Services/KinesisStreamConsumer.cs | 4 +- .../Services/KinesisTracker.cs | 4 +- .../Services/SQSQueueProvider.cs | 4 +- .../DynamoPersistenceProviderFixture.cs | 5 ++- 9 files changed, 40 insertions(+), 30 deletions(-) diff --git a/src/providers/WorkflowCore.Providers.AWS/ServiceCollectionExtensions.cs b/src/providers/WorkflowCore.Providers.AWS/ServiceCollectionExtensions.cs index 171860524..5d62bf3dc 100644 --- a/src/providers/WorkflowCore.Providers.AWS/ServiceCollectionExtensions.cs +++ b/src/providers/WorkflowCore.Providers.AWS/ServiceCollectionExtensions.cs @@ -1,6 +1,7 @@ using System; using Amazon; using Amazon.DynamoDBv2; +using Amazon.Kinesis; using Amazon.Runtime; using Amazon.SQS; using Microsoft.Extensions.Logging; @@ -15,47 +16,55 @@ public static class ServiceCollectionExtensions { public static WorkflowOptions UseAwsSimpleQueueService(this WorkflowOptions options, AWSCredentials credentials, AmazonSQSConfig config, string queuesPrefix = "workflowcore") { - options.UseQueueProvider(sp => new SQSQueueProvider(credentials, config, null, sp.GetService(), queuesPrefix)); - return options; + var sqsClient = new AmazonSQSClient(credentials, config); + return UseAwsSimpleQueueServiceWithProvisionedClient(options, sqsClient, queuesPrefix); } public static WorkflowOptions UseAwsSimpleQueueServiceWithProvisionedClient(this WorkflowOptions options, AmazonSQSClient sqsClient, string queuesPrefix = "workflowcore") { - options.UseQueueProvider(sp => new SQSQueueProvider(null, null, sqsClient, sp.GetService(), queuesPrefix)); + options.UseQueueProvider(sp => new SQSQueueProvider(sqsClient, sp.GetService(), queuesPrefix)); return options; } public static WorkflowOptions UseAwsDynamoLocking(this WorkflowOptions options, AWSCredentials credentials, AmazonDynamoDBConfig config, string tableName) { - options.UseDistributedLockManager(sp => new DynamoLockProvider(credentials, config, null, tableName, sp.GetService(), sp.GetService())); - return options; + var dbClient = new AmazonDynamoDBClient(credentials, config); + return UseAwsDynamoLockingWithProvisionedClient(options, dbClient, tableName); } public static WorkflowOptions UseAwsDynamoLockingWithProvisionedClient (this WorkflowOptions options, AmazonDynamoDBClient dynamoClient, string tableName) { - options.UseDistributedLockManager(sp => new DynamoLockProvider(null, null, dynamoClient, tableName, sp.GetService(), sp.GetService())); + options.UseDistributedLockManager(sp => new DynamoLockProvider(dynamoClient, tableName, sp.GetService(), sp.GetService())); return options; } public static WorkflowOptions UseAwsDynamoPersistence(this WorkflowOptions options, AWSCredentials credentials, AmazonDynamoDBConfig config, string tablePrefix) { - options.Services.AddTransient(sp => new DynamoDbProvisioner(credentials, config, null, tablePrefix, sp.GetService())); - options.UsePersistence(sp => new DynamoPersistenceProvider(credentials, config, null, sp.GetService(), tablePrefix, sp.GetService())); - return options; + var dbClient = new AmazonDynamoDBClient(credentials, config); + return UseAwsDynamoPersistenceWithProvisionedClient(options, dbClient, tablePrefix); } public static WorkflowOptions UseAwsDynamoPersistenceWithProvisionedClient(this WorkflowOptions options, AmazonDynamoDBClient dynamoClient, string tablePrefix) { - options.Services.AddTransient(sp => new DynamoDbProvisioner(null, null, dynamoClient, tablePrefix, sp.GetService())); - options.UsePersistence(sp => new DynamoPersistenceProvider(null, null, dynamoClient, sp.GetService(), tablePrefix, sp.GetService())); + options.Services.AddTransient(sp => new DynamoDbProvisioner(dynamoClient, tablePrefix, sp.GetService())); + options.UsePersistence(sp => new DynamoPersistenceProvider(dynamoClient, sp.GetService(), tablePrefix, sp.GetService())); return options; } public static WorkflowOptions UseAwsKinesis(this WorkflowOptions options, AWSCredentials credentials, RegionEndpoint region, string appName, string streamName) { - options.Services.AddTransient(sp => new KinesisTracker(credentials, region, "workflowcore_kinesis", sp.GetService())); - options.Services.AddTransient(sp => new KinesisStreamConsumer(credentials, region, sp.GetService(), sp.GetService(), sp.GetService(), sp.GetService())); - options.UseEventHub(sp => new KinesisProvider(credentials, region, appName, streamName, sp.GetService(), sp.GetService())); + var kinesisClient = new AmazonKinesisClient(credentials, region); + var dynamoClient = new AmazonDynamoDBClient(credentials, region); + + return UseAwsKinesisWithProvisionedClients(options, kinesisClient, dynamoClient,appName, streamName); + + } + + public static WorkflowOptions UseAwsKinesisWithProvisionedClients(this WorkflowOptions options, AmazonKinesisClient kinesisClient, AmazonDynamoDBClient dynamoDbClient, string appName, string streamName) + { + options.Services.AddTransient(sp => new KinesisTracker(dynamoDbClient, "workflowcore_kinesis", sp.GetService())); + options.Services.AddTransient(sp => new KinesisStreamConsumer(kinesisClient, sp.GetService(), sp.GetService(), sp.GetService(), sp.GetService())); + options.UseEventHub(sp => new KinesisProvider(kinesisClient, appName, streamName, sp.GetService(), sp.GetService())); return options; } } diff --git a/src/providers/WorkflowCore.Providers.AWS/Services/DynamoDbProvisioner.cs b/src/providers/WorkflowCore.Providers.AWS/Services/DynamoDbProvisioner.cs index 6d3c712b7..887d11a7a 100644 --- a/src/providers/WorkflowCore.Providers.AWS/Services/DynamoDbProvisioner.cs +++ b/src/providers/WorkflowCore.Providers.AWS/Services/DynamoDbProvisioner.cs @@ -15,10 +15,10 @@ public class DynamoDbProvisioner : IDynamoDbProvisioner private readonly IAmazonDynamoDB _client; private readonly string _tablePrefix; - public DynamoDbProvisioner(AWSCredentials credentials, AmazonDynamoDBConfig config, AmazonDynamoDBClient dynamoDBClient, string tablePrefix, ILoggerFactory logFactory) + public DynamoDbProvisioner(AmazonDynamoDBClient dynamoDBClient, string tablePrefix, ILoggerFactory logFactory) { _logger = logFactory.CreateLogger(); - _client = dynamoDBClient ?? new AmazonDynamoDBClient(credentials, config); + _client = dynamoDBClient; _tablePrefix = tablePrefix; } diff --git a/src/providers/WorkflowCore.Providers.AWS/Services/DynamoLockProvider.cs b/src/providers/WorkflowCore.Providers.AWS/Services/DynamoLockProvider.cs index 32ebe488b..0863f1393 100644 --- a/src/providers/WorkflowCore.Providers.AWS/Services/DynamoLockProvider.cs +++ b/src/providers/WorkflowCore.Providers.AWS/Services/DynamoLockProvider.cs @@ -25,10 +25,10 @@ public class DynamoLockProvider : IDistributedLockProvider private readonly AutoResetEvent _mutex = new AutoResetEvent(true); private readonly IDateTimeProvider _dateTimeProvider; - public DynamoLockProvider(AWSCredentials credentials, AmazonDynamoDBConfig config, AmazonDynamoDBClient dynamoDBClient, string tableName, ILoggerFactory logFactory, IDateTimeProvider dateTimeProvider) + public DynamoLockProvider(AmazonDynamoDBClient dynamoDBClient, string tableName, ILoggerFactory logFactory, IDateTimeProvider dateTimeProvider) { _logger = logFactory.CreateLogger(); - _client = dynamoDBClient ?? new AmazonDynamoDBClient(credentials, config); + _client = dynamoDBClient; _localLocks = new List(); _tableName = tableName; _nodeId = Guid.NewGuid().ToString(); diff --git a/src/providers/WorkflowCore.Providers.AWS/Services/DynamoPersistenceProvider.cs b/src/providers/WorkflowCore.Providers.AWS/Services/DynamoPersistenceProvider.cs index 0c78c6048..01beaaabe 100644 --- a/src/providers/WorkflowCore.Providers.AWS/Services/DynamoPersistenceProvider.cs +++ b/src/providers/WorkflowCore.Providers.AWS/Services/DynamoPersistenceProvider.cs @@ -26,10 +26,10 @@ public class DynamoPersistenceProvider : IPersistenceProvider public bool SupportsScheduledCommands => false; - public DynamoPersistenceProvider(AWSCredentials credentials, AmazonDynamoDBConfig config, AmazonDynamoDBClient dynamoDBClient, IDynamoDbProvisioner provisioner, string tablePrefix, ILoggerFactory logFactory) + public DynamoPersistenceProvider(AmazonDynamoDBClient dynamoDBClient, IDynamoDbProvisioner provisioner, string tablePrefix, ILoggerFactory logFactory) { _logger = logFactory.CreateLogger(); - _client = dynamoDBClient ?? new AmazonDynamoDBClient(credentials, config); + _client = dynamoDBClient; _tablePrefix = tablePrefix; _provisioner = provisioner; } diff --git a/src/providers/WorkflowCore.Providers.AWS/Services/KinesisProvider.cs b/src/providers/WorkflowCore.Providers.AWS/Services/KinesisProvider.cs index 99d43d94f..d8aa519bd 100644 --- a/src/providers/WorkflowCore.Providers.AWS/Services/KinesisProvider.cs +++ b/src/providers/WorkflowCore.Providers.AWS/Services/KinesisProvider.cs @@ -26,7 +26,7 @@ public class KinesisProvider : ILifeCycleEventHub private readonly int _defaultShardCount = 1; private bool _started = false; - public KinesisProvider(AWSCredentials credentials, RegionEndpoint region, string appName, string streamName, IKinesisStreamConsumer consumer, ILoggerFactory logFactory) + public KinesisProvider(AmazonKinesisClient kinesisClient, string appName, string streamName, IKinesisStreamConsumer consumer, ILoggerFactory logFactory) { _logger = logFactory.CreateLogger(GetType()); _appName = appName; @@ -34,7 +34,7 @@ public KinesisProvider(AWSCredentials credentials, RegionEndpoint region, string _consumer = consumer; _serializer = new JsonSerializer(); _serializer.TypeNameHandling = TypeNameHandling.All; - _client = new AmazonKinesisClient(credentials, region); + _client = kinesisClient; } public async Task PublishNotification(LifeCycleEvent evt) diff --git a/src/providers/WorkflowCore.Providers.AWS/Services/KinesisStreamConsumer.cs b/src/providers/WorkflowCore.Providers.AWS/Services/KinesisStreamConsumer.cs index 799125a0d..5c89f7837 100644 --- a/src/providers/WorkflowCore.Providers.AWS/Services/KinesisStreamConsumer.cs +++ b/src/providers/WorkflowCore.Providers.AWS/Services/KinesisStreamConsumer.cs @@ -25,12 +25,12 @@ public class KinesisStreamConsumer : IKinesisStreamConsumer, IDisposable private ICollection _subscribers = new HashSet(); private readonly IDateTimeProvider _dateTimeProvider; - public KinesisStreamConsumer(AWSCredentials credentials, RegionEndpoint region, IKinesisTracker tracker, IDistributedLockProvider lockManager, ILoggerFactory logFactory, IDateTimeProvider dateTimeProvider) + public KinesisStreamConsumer(AmazonKinesisClient kinesisClient, IKinesisTracker tracker, IDistributedLockProvider lockManager, ILoggerFactory logFactory, IDateTimeProvider dateTimeProvider) { _logger = logFactory.CreateLogger(GetType()); _tracker = tracker; _lockManager = lockManager; - _client = new AmazonKinesisClient(credentials, region); + _client = kinesisClient; _processTask = new Task(Process); _processTask.Start(); _dateTimeProvider = dateTimeProvider; diff --git a/src/providers/WorkflowCore.Providers.AWS/Services/KinesisTracker.cs b/src/providers/WorkflowCore.Providers.AWS/Services/KinesisTracker.cs index 9c5548420..d7c028c46 100644 --- a/src/providers/WorkflowCore.Providers.AWS/Services/KinesisTracker.cs +++ b/src/providers/WorkflowCore.Providers.AWS/Services/KinesisTracker.cs @@ -17,10 +17,10 @@ public class KinesisTracker : IKinesisTracker private readonly string _tableName; private bool _tableConfirmed = false; - public KinesisTracker(AWSCredentials credentials, RegionEndpoint region, string tableName, ILoggerFactory logFactory) + public KinesisTracker(AmazonDynamoDBClient client, string tableName, ILoggerFactory logFactory) { _logger = logFactory.CreateLogger(GetType()); - _client = new AmazonDynamoDBClient(credentials, region); + _client = client; _tableName = tableName; } diff --git a/src/providers/WorkflowCore.Providers.AWS/Services/SQSQueueProvider.cs b/src/providers/WorkflowCore.Providers.AWS/Services/SQSQueueProvider.cs index af2c40b20..c15fb02af 100644 --- a/src/providers/WorkflowCore.Providers.AWS/Services/SQSQueueProvider.cs +++ b/src/providers/WorkflowCore.Providers.AWS/Services/SQSQueueProvider.cs @@ -21,10 +21,10 @@ public class SQSQueueProvider : IQueueProvider public bool IsDequeueBlocking => true; - public SQSQueueProvider(AWSCredentials credentials, AmazonSQSConfig config, AmazonSQSClient sqsClient, ILoggerFactory logFactory, string queuesPrefix) + public SQSQueueProvider(AmazonSQSClient sqsClient, ILoggerFactory logFactory, string queuesPrefix) { _logger = logFactory.CreateLogger(); - _client = sqsClient ?? new AmazonSQSClient(credentials, config); + _client = sqsClient; _queuesPrefix = queuesPrefix; } diff --git a/test/WorkflowCore.Tests.DynamoDB/DynamoPersistenceProviderFixture.cs b/test/WorkflowCore.Tests.DynamoDB/DynamoPersistenceProviderFixture.cs index 6ec1c13b6..7d215f4ee 100644 --- a/test/WorkflowCore.Tests.DynamoDB/DynamoPersistenceProviderFixture.cs +++ b/test/WorkflowCore.Tests.DynamoDB/DynamoPersistenceProviderFixture.cs @@ -26,8 +26,9 @@ protected override IPersistenceProvider Subject if (_subject == null) { var cfg = new AmazonDynamoDBConfig { ServiceURL = DynamoDbDockerSetup.ConnectionString }; - var provisioner = new DynamoDbProvisioner(DynamoDbDockerSetup.Credentials, cfg, null, "unittests", new LoggerFactory()); - var client = new DynamoPersistenceProvider(DynamoDbDockerSetup.Credentials, cfg, null, provisioner, "unittests", new LoggerFactory()); + var dbClient = new AmazonDynamoDBClient(DynamoDbDockerSetup.Credentials, cfg); + var provisioner = new DynamoDbProvisioner(dbClient, "unittests", new LoggerFactory()); + var client = new DynamoPersistenceProvider(dbClient, provisioner, "unittests", new LoggerFactory()); client.EnsureStoreExists(); _subject = client; } From e1829f8174d78c03852ac16281b9b1c084ef7347 Mon Sep 17 00:00:00 2001 From: Stuart McKenzie Date: Fri, 28 Apr 2023 11:40:23 +1000 Subject: [PATCH 5/9] better patterns in the Service Collection Extensions (use the extension methods as intended) --- .../ServiceCollectionExtensions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/providers/WorkflowCore.Providers.AWS/ServiceCollectionExtensions.cs b/src/providers/WorkflowCore.Providers.AWS/ServiceCollectionExtensions.cs index 5d62bf3dc..c3c545f80 100644 --- a/src/providers/WorkflowCore.Providers.AWS/ServiceCollectionExtensions.cs +++ b/src/providers/WorkflowCore.Providers.AWS/ServiceCollectionExtensions.cs @@ -17,7 +17,7 @@ public static class ServiceCollectionExtensions public static WorkflowOptions UseAwsSimpleQueueService(this WorkflowOptions options, AWSCredentials credentials, AmazonSQSConfig config, string queuesPrefix = "workflowcore") { var sqsClient = new AmazonSQSClient(credentials, config); - return UseAwsSimpleQueueServiceWithProvisionedClient(options, sqsClient, queuesPrefix); + return options.UseAwsSimpleQueueServiceWithProvisionedClient(sqsClient, queuesPrefix); } public static WorkflowOptions UseAwsSimpleQueueServiceWithProvisionedClient(this WorkflowOptions options, AmazonSQSClient sqsClient, string queuesPrefix = "workflowcore") @@ -29,7 +29,7 @@ public static WorkflowOptions UseAwsSimpleQueueServiceWithProvisionedClient(this public static WorkflowOptions UseAwsDynamoLocking(this WorkflowOptions options, AWSCredentials credentials, AmazonDynamoDBConfig config, string tableName) { var dbClient = new AmazonDynamoDBClient(credentials, config); - return UseAwsDynamoLockingWithProvisionedClient(options, dbClient, tableName); + return options.UseAwsDynamoLockingWithProvisionedClient(dbClient, tableName); } public static WorkflowOptions UseAwsDynamoLockingWithProvisionedClient (this WorkflowOptions options, AmazonDynamoDBClient dynamoClient, string tableName) @@ -41,7 +41,7 @@ public static WorkflowOptions UseAwsDynamoLockingWithProvisionedClient (this Wor public static WorkflowOptions UseAwsDynamoPersistence(this WorkflowOptions options, AWSCredentials credentials, AmazonDynamoDBConfig config, string tablePrefix) { var dbClient = new AmazonDynamoDBClient(credentials, config); - return UseAwsDynamoPersistenceWithProvisionedClient(options, dbClient, tablePrefix); + return options.UseAwsDynamoPersistenceWithProvisionedClient(dbClient, tablePrefix); } public static WorkflowOptions UseAwsDynamoPersistenceWithProvisionedClient(this WorkflowOptions options, AmazonDynamoDBClient dynamoClient, string tablePrefix) @@ -56,7 +56,7 @@ public static WorkflowOptions UseAwsKinesis(this WorkflowOptions options, AWSCre var kinesisClient = new AmazonKinesisClient(credentials, region); var dynamoClient = new AmazonDynamoDBClient(credentials, region); - return UseAwsKinesisWithProvisionedClients(options, kinesisClient, dynamoClient,appName, streamName); + return options.UseAwsKinesisWithProvisionedClients(kinesisClient, dynamoClient,appName, streamName); } From b7de0a1bff9668f14bdb629b3c39a82da79cb7f5 Mon Sep 17 00:00:00 2001 From: Daniel Gerlag Date: Tue, 9 May 2023 08:25:04 -0700 Subject: [PATCH 6/9] Update Directory.Build.props --- src/Directory.Build.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index a617157cb..19614367d 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,10 +4,10 @@ https://github.com/danielgerlag/workflow-core/blob/master/LICENSE.md git https://github.com/danielgerlag/workflow-core.git - 3.8.2 - 3.8.2.0 - 3.8.2.0 + 3.8.3 + 3.8.3.0 + 3.8.3.0 https://github.com/danielgerlag/workflow-core/raw/master/src/logo.png - 3.8.2 + 3.8.3 From a423a7e72291e7ed257e2f25ec5dc2b48877ba08 Mon Sep 17 00:00:00 2001 From: Ben Edwards Date: Wed, 17 May 2023 12:42:16 +1000 Subject: [PATCH 7/9] Update EFCore to 7 Change all .net 6 package references to entity framework to 7.*. All tests pass :D --- .../WorkflowCore.Persistence.EntityFramework.csproj | 2 +- .../WorkflowCore.Persistence.MySQL.csproj | 4 ++-- .../WorkflowCore.Persistence.PostgreSQL.csproj | 8 ++++---- .../WorkflowCore.Persistence.SqlServer.csproj | 6 +++--- .../WorkflowCore.Persistence.Sqlite.csproj | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/providers/WorkflowCore.Persistence.EntityFramework/WorkflowCore.Persistence.EntityFramework.csproj b/src/providers/WorkflowCore.Persistence.EntityFramework/WorkflowCore.Persistence.EntityFramework.csproj index 6ab835915..b5fb079c9 100644 --- a/src/providers/WorkflowCore.Persistence.EntityFramework/WorkflowCore.Persistence.EntityFramework.csproj +++ b/src/providers/WorkflowCore.Persistence.EntityFramework/WorkflowCore.Persistence.EntityFramework.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/providers/WorkflowCore.Persistence.MySQL/WorkflowCore.Persistence.MySQL.csproj b/src/providers/WorkflowCore.Persistence.MySQL/WorkflowCore.Persistence.MySQL.csproj index aaf1f79b0..8b87ba216 100644 --- a/src/providers/WorkflowCore.Persistence.MySQL/WorkflowCore.Persistence.MySQL.csproj +++ b/src/providers/WorkflowCore.Persistence.MySQL/WorkflowCore.Persistence.MySQL.csproj @@ -35,11 +35,11 @@ - + all runtime; build; native; contentfiles; analyzers - + diff --git a/src/providers/WorkflowCore.Persistence.PostgreSQL/WorkflowCore.Persistence.PostgreSQL.csproj b/src/providers/WorkflowCore.Persistence.PostgreSQL/WorkflowCore.Persistence.PostgreSQL.csproj index e321a340a..583c706f0 100644 --- a/src/providers/WorkflowCore.Persistence.PostgreSQL/WorkflowCore.Persistence.PostgreSQL.csproj +++ b/src/providers/WorkflowCore.Persistence.PostgreSQL/WorkflowCore.Persistence.PostgreSQL.csproj @@ -23,12 +23,12 @@ - - - + + + All - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/providers/WorkflowCore.Persistence.SqlServer/WorkflowCore.Persistence.SqlServer.csproj b/src/providers/WorkflowCore.Persistence.SqlServer/WorkflowCore.Persistence.SqlServer.csproj index be099421a..b6db766bd 100644 --- a/src/providers/WorkflowCore.Persistence.SqlServer/WorkflowCore.Persistence.SqlServer.csproj +++ b/src/providers/WorkflowCore.Persistence.SqlServer/WorkflowCore.Persistence.SqlServer.csproj @@ -24,11 +24,11 @@ - - + + All - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/providers/WorkflowCore.Persistence.Sqlite/WorkflowCore.Persistence.Sqlite.csproj b/src/providers/WorkflowCore.Persistence.Sqlite/WorkflowCore.Persistence.Sqlite.csproj index 0bd622bde..88b9ceec9 100644 --- a/src/providers/WorkflowCore.Persistence.Sqlite/WorkflowCore.Persistence.Sqlite.csproj +++ b/src/providers/WorkflowCore.Persistence.Sqlite/WorkflowCore.Persistence.Sqlite.csproj @@ -24,7 +24,7 @@ - + From 12be88701780e1f1b2d5b5b5d98e7ce4df3e9913 Mon Sep 17 00:00:00 2001 From: Daniel Gerlag Date: Tue, 13 Jun 2023 07:32:25 -0700 Subject: [PATCH 8/9] Update Directory.Build.props --- src/Directory.Build.props | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 19614367d..5d86bd3a5 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,10 +4,10 @@ https://github.com/danielgerlag/workflow-core/blob/master/LICENSE.md git https://github.com/danielgerlag/workflow-core.git - 3.8.3 - 3.8.3.0 - 3.8.3.0 + 3.9.0 + 3.9.0.0 + 3.9.0.0 https://github.com/danielgerlag/workflow-core/raw/master/src/logo.png - 3.8.3 + 3.9.0 From 11d461c6bd1f87fd820f22078a7f756414b637dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 27 Jun 2023 23:11:13 +0000 Subject: [PATCH 9/9] Bump System.Linq.Dynamic.Core in /src/WorkflowCore.DSL Bumps [System.Linq.Dynamic.Core](https://github.com/zzzprojects/System.Linq.Dynamic.Core) from 1.2.13 to 1.3.0. - [Release notes](https://github.com/zzzprojects/System.Linq.Dynamic.Core/releases) - [Changelog](https://github.com/zzzprojects/System.Linq.Dynamic.Core/blob/master/CHANGELOG.md) - [Commits](https://github.com/zzzprojects/System.Linq.Dynamic.Core/compare/v1.2.13...v1.3.0) --- updated-dependencies: - dependency-name: System.Linq.Dynamic.Core dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- src/WorkflowCore.DSL/WorkflowCore.DSL.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WorkflowCore.DSL/WorkflowCore.DSL.csproj b/src/WorkflowCore.DSL/WorkflowCore.DSL.csproj index b3ce61cef..94765a53e 100644 --- a/src/WorkflowCore.DSL/WorkflowCore.DSL.csproj +++ b/src/WorkflowCore.DSL/WorkflowCore.DSL.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -11,7 +11,7 @@ - +