How to: Reduce the Memory Consumption of the Workflow Service

The current Workflow Server implementation is not designed for the scenario when workflow definitions are changed very frequently (1 minute), and an updated version should be started in a short time. The refresh operation is executed with the help of the HostManagerActivityProvider class that uses the AssemblyBuilder class to create activities from XAML strings. This approach allows end-users to add runtime activities on the toolbox and to reuse these activities as components in the runtime workflow designer. So, with each refresh operation, a new assembly is created and loaded into the current AppDomain. This operation requires additional unmanaged memory (about 100Kb per each assembly). All the loaded assemblies are unloaded when the entire AppDomain object is unloaded. The HostManagerActivityProvider class does not make any checks and always creates a new assembly. That is why the used unmanaged memory grows constantly. This topic illustrates how to implement a custom HostManagerActivityProvider class that does not require additional memory, but does not allow reusing runtime activities.

Note
  • Alternatively, you can raise the RefreshWorkflowDefinitionsService.DelayPeriod value to an hour (see Workflow Server Service), and manually force the refresh operation when necessary.
  • Mobile applications do not support the Workflow Module, so the approach described in this topic cannot be implemented in the Mobile platform.
  • Add the following class to the Workflow Server Service project.

    using System.IO;
    using System.Activities;
    using System.Activities.XamlIntegration;
    using DevExpress.ExpressApp.Workflow;
    using DevExpress.ExpressApp.Workflow.Server;
    using DevExpress.ExpressApp.Workflow.CommonServices;
    // ...
    public class CustomHostManagerActivityProvider : DevExpress.ExpressApp.Workflow.Server.WorkflowServerService {
        private void Manager_HostOpening(object sender, EventArgs e) {
            IList<IWorkflowDefinition> definitions = 
                GetService<IWorkflowDefinitionProvider>().GetDefinitions();
            Dictionary<string, Activity> activities = new Dictionary<string, Activity>();
            foreach(IWorkflowDefinition definition in definitions) {
                if(definition.CanOpenHost) {
                    Activity activity = ActivityXamlServices.Load(new StringReader(definition.Xaml));
                    activity.DisplayName = definition.GetActivityTypeName();
                    activities.Add(definition.GetUniqueId(), activity);
                }
            }
            HostManager.RefreshHosts(activities);
        }
        protected override void OnInitialized() {
            base.OnInitialized();
            HostManager.HostsOpening += new EventHandler(Manager_HostOpening);
        }
    }
    
  • Open the WorkflowServerService.cs (WorkflowServerService.vb) file. In the OnStart method, assign an instance of the CustomHostManagerActivityProvider class to the WorkflowServer.HostManagerActivityProvider property.

    server = new WorkflowServer("http://localhost:46232", objectSpaceProvider, objectSpaceProvider);
    server.HostManagerActivityProvider = new CustomHostManagerActivityProvider();
    
See Also