This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

M-Files Configuration Frequency Interval

I am working on setting up something in my configuration that includes a RecurringOperationConfiguration

I have it working for schedule without any issue but when I try and lookup Interval it seems a bit vague and I don't really understand what the Time Value in the configuration is for.

It says it is configurable but I don't quite understand how to control the interval from the admin if it's giving me a Time Value. I've ready the following and haven't clued in on what I should be doing to allow the admin to decide what the interval should be/

https://developer.m-files.com/Frameworks/Vault-Application-Framework/Task-Queues/Recurring-Tasks/

What do I need to do for the admin to be able to set something like run every 2 hours?

Parents Reply Children
  • So I am having an issue with this in general, maybe I am doing something wrong but interval only runs once and then never runs again. My interval settings are:

     (every 3 minutes)

    Which shows that it will run every 3 minutes, but also says stopped in the top right:

    Ignore the error, that was just me testing something else.

    Ultimately I am using a TaskProcessor to do something every x minutes.

    [TaskProcessor(QueueId, POTimeLoopApp1)]
    public void POTimeLoop1(ITaskProcessingJob<TaskDirective> job)

    Is there something else I should be doing here? A better way to do this? After the first run it just switches to Stopped and never runs again. 

  • It should only show stopped if the task never gets scheduled for the future. As the interval itself is being read properly it makes me wonder whether something is interfering with the reschedule.

    Any errors in the processing, overriding any methods on the vault application?

    Could you share the application with me to take a look at? 

  • I cannot share the entire application but here is the code for the task, I know it's not the best and I am more focused on getting the functionality working but I feel like I am missing something? Everything works properly when on a schedule, just not an interval:

    I've Updated my code to make use of transactionalVault and not my old login method:

    [TaskProcessor(QueueId, POTimeLoopApp2)]
            public void POTimeLoop2(ITaskProcessingJob<TaskDirective> job)
            {
                //try
                //{
    
                //this sends a message to the dashboard saying the operation is complete
                job.Commit((transactionalVault) =>
                {
                    string today = System.DateTime.Now.ToString("dddd");
                    if ((today == "Saturday" || today == "Sunday" || today == "Samedi" || today == "Dimanche") && this.Configuration.POTimeLoop.POTimeLoop2Settings.SkipWeekends == false)
                    {
                        //get IDs for configurations to check if they have been entered
                        int classID = this.Configuration?.POTimeLoop?.POTimeLoop2Settings?.ClassToRunOn?.ID ?? -1;
                        int startStateID = this.Configuration?.POTimeLoop?.POTimeLoop2Settings?.StartWorkflowAndState?.State?.ID ?? -1;
                        int endStateID = this.Configuration?.POTimeLoop?.POTimeLoop2Settings?.StartWorkflowAndState?.State?.ID ?? -1;
                        int incrementProperty = this.Configuration?.POTimeLoop?.POTimeLoop2Settings?.IncrementPropertyInteger?.ID ?? -1;
    
                        //Vault Vault;
    
                        //if the authentication, class, start and end state, and is enabled then proceed
                        if (this.Configuration.POTimeLoop.POTimeLoop2Settings.Enabled == true
                    && classID > -1
                    && startStateID > -1
                    && endStateID > -1
                    && this.Configuration.POTimeLoop.POTimeLoop2Settings.LocalVaultGUID != null
                    && this.Configuration.POTimeLoop.POTimeLoop2Settings.AuthenticationType != null
                    && this.Configuration.POTimeLoop.POTimeLoop2Settings.Login != null
                    && this.Configuration.POTimeLoop.POTimeLoop2Settings.Password != null)
                        {
                            ////create connection and connect to the vault, if the authentication type is MFiles user, login accordingly
                            //if (this.Configuration.POTimeLoop.POTimeLoop2Settings.AuthenticationType == "2")
                            //{
                            //    MFilesServerApplication oApp = new MFilesServerApplication();
                            //    oApp.Connect(MFAuthType.MFAuthTypeSpecificMFilesUser, this.Configuration.POTimeLoop.POTimeLoop2Settings.Login, this.Configuration.POTimeLoop.POTimeLoop2Settings.Password, "", "ncacn_ip_tcp",
                            //        "localhost", "2266", "", false);
                            //    Vault = oApp.LogInToVault(this.Configuration.POTimeLoop.POTimeLoop2Settings.LocalVaultGUID);
                            //}
                            ////if not mfiles user authentication then login using specific windows user
                            //else
                            //{
                            //    MFilesServerApplication oApp = new MFilesServerApplication();
                            //    oApp.Connect(MFAuthType.MFAuthTypeSpecificWindowsUser, this.Configuration.POTimeLoop.POTimeLoop2Settings.Login, this.Configuration.POTimeLoop.POTimeLoop2Settings.Password, "", "ncacn_ip_tcp",
                            //        "localhost", "2266", "", false);
                            //    Vault = oApp.LogInToVault(this.Configuration.POTimeLoop.POTimeLoop2Settings.LocalVaultGUID);
                            //}
    
                            //if logged in
                            //if (Vault.LoggedIn == true)
                            //{
                            //search for all the objects in that class and in that state
                            MFSearchBuilder poTimeLoopSearch = new MFSearchBuilder(transactionalVault);
    
                            //if deleted and loop through the classes
                            poTimeLoopSearch.Deleted(false);
                            poTimeLoopSearch.Class(this.Configuration.POTimeLoop.POTimeLoop2Settings.ClassToRunOn.ID);
                            poTimeLoopSearch.Property(39, MFDataType.MFDatatypeLookup, this.Configuration.POTimeLoop.POTimeLoop2Settings.StartWorkflowAndState.State.ID);
    
                            var results = poTimeLoopSearch.Find();
    
                            //loop through the results
                            if (results.Count > 0)
                            {
                                for (int i = 1; i <= results.Count; i++)
                                {
                                    ObjVerEx objectToLoop = new ObjVerEx(transactionalVault, results[i].ObjVer);
    
                                    //if the increment is not empty, increase it by 1 and change the state
                                    if (objectToLoop.GetProperty(this.Configuration.POTimeLoop.POTimeLoop2Settings.IncrementPropertyInteger.ID).TypedValue.DisplayValue != "")
                                    {
                                        PropertyValues properties = new PropertyValues();
    
                                        properties.Add(-1, newObject.createPropertyValueLookup(39, this.Configuration.POTimeLoop.POTimeLoop2Settings.EndWorkflowAndState.State.ID));
    
                                        int incrementValue = Int32.Parse(objectToLoop.GetProperty(this.Configuration.POTimeLoop.POTimeLoop2Settings.IncrementPropertyInteger.ID).TypedValue.DisplayValue);
                                        incrementValue++;
                                        properties.Add(-1, newObject.createPropertyValueInt(this.Configuration.POTimeLoop.POTimeLoop2Settings.IncrementPropertyInteger.ID, incrementValue));
                                        objectToLoop.SaveProperties(properties);
                                    }
                                    //if the increment is empty set it to 0 and change the state
                                    else
                                    {
                                        PropertyValues properties = new PropertyValues();
    
                                        properties.Add(-1, newObject.createPropertyValueLookup(39, this.Configuration.POTimeLoop.POTimeLoop2Settings.EndWorkflowAndState.State.ID));
    
                                        properties.Add(-1, newObject.createPropertyValueInt(this.Configuration.POTimeLoop.POTimeLoop2Settings.IncrementPropertyInteger.ID, 1));
                                        objectToLoop.SaveProperties(properties);
                                    }
                                }
                            }
                        }
                    }
                });

  • [TaskProcessor(QueueId, POTimeLoopApp1)]
            public void POTimeLoop1(ITaskProcessingJob<TaskDirective> job)
            {
                //try
                //{
                string today = System.DateTime.Now.ToString("dddd");
                if ((today == "Saturday" || today == "Sunday" || today == "Samedi" || today == "Dimanche") && this.Configuration.POTimeLoop.POTimeLoop1Settings.SkipWeekends == false)
                {
                    //get IDs for configurations to check if they have been entered
                    int classID = this.Configuration?.POTimeLoop?.POTimeLoop1Settings?.ClassToRunOn?.ID ?? -1;
                    int startStateID = this.Configuration?.POTimeLoop?.POTimeLoop1Settings?.StartWorkflowAndState?.State?.ID ?? -1;
                    int endStateID = this.Configuration?.POTimeLoop?.POTimeLoop1Settings?.StartWorkflowAndState?.State?.ID ?? -1;
                    int incrementProperty = this.Configuration?.POTimeLoop?.POTimeLoop1Settings?.IncrementPropertyInteger?.ID ?? -1;
    
                    Vault Vault;
    
                    //if the authentication, class, start and end state, and is enabled then proceed
                    if (this.Configuration.POTimeLoop.POTimeLoop1Settings.Enabled == true
                        && classID > -1
                        && startStateID > -1
                        && endStateID > -1
                        && this.Configuration.POTimeLoop.POTimeLoop1Settings.LocalVaultGUID != null
                        && this.Configuration.POTimeLoop.POTimeLoop1Settings.AuthenticationType != null
                        && this.Configuration.POTimeLoop.POTimeLoop1Settings.Login != null
                        && this.Configuration.POTimeLoop.POTimeLoop1Settings.Password != null)
                    {
                        //create connection and connect to the vault, if the authentication type is MFiles user, login accordingly
                        if (this.Configuration.POTimeLoop.POTimeLoop1Settings.AuthenticationType == "2")
                        {
                            MFilesServerApplication oApp = new MFilesServerApplication();
                            oApp.Connect(MFAuthType.MFAuthTypeSpecificMFilesUser, this.Configuration.POTimeLoop.POTimeLoop1Settings.Login, this.Configuration.POTimeLoop.POTimeLoop1Settings.Password, "", "ncacn_ip_tcp",
                                "localhost", "2266", "", false);
                            Vault = oApp.LogInToVault(this.Configuration.POTimeLoop.POTimeLoop1Settings.LocalVaultGUID);
                        }
                        //if not mfiles user authentication then login using specific windows user
                        else
                        {
                            MFilesServerApplication oApp = new MFilesServerApplication();
                            oApp.Connect(MFAuthType.MFAuthTypeSpecificWindowsUser, this.Configuration.POTimeLoop.POTimeLoop1Settings.Login, this.Configuration.POTimeLoop.POTimeLoop1Settings.Password, "", "ncacn_ip_tcp",
                                "localhost", "2266", "", false);
                            Vault = oApp.LogInToVault(this.Configuration.POTimeLoop.POTimeLoop1Settings.LocalVaultGUID);
                        }
    
                        //if logged in
                        if (Vault.LoggedIn == true)
                        {
                            //search for all the objects in that class and in that state
                            MFSearchBuilder poTimeLoopSearch = new MFSearchBuilder(Vault);
    
                            //if deleted and loop through the classes
                            poTimeLoopSearch.Deleted(false);
                            poTimeLoopSearch.Class(this.Configuration.POTimeLoop.POTimeLoop1Settings.ClassToRunOn.ID);
                            poTimeLoopSearch.Property(39, MFDataType.MFDatatypeLookup, this.Configuration.POTimeLoop.POTimeLoop1Settings.StartWorkflowAndState.State.ID);
    
                            var results = poTimeLoopSearch.Find();
    
                            //loop through the results
                            if (results.Count > 0)
                            {
                                for (int i = 1; i <= results.Count; i++)
                                {
                                    ObjVerEx objectToLoop = new ObjVerEx(Vault, results[i].ObjVer);
    
                                    DateTime lastModified = DateTime.Parse(objectToLoop.GetProperty(21).TypedValue.DisplayValue, CultureInfo.InvariantCulture, DateTimeStyles.None);
                                    DateTime Now = DateTime.Now;
                                    TimeSpan minutesBetween = (Now - lastModified);
    
                                    if (minutesBetween.TotalMinutes >= this.Configuration.POTimeLoop.POTimeLoop1Settings.MinutesSinceLastUpdate)
                                    {
                                        //if the increment is not empty, increase it by 1 and change the state
                                        if (objectToLoop.GetProperty(this.Configuration.POTimeLoop.POTimeLoop1Settings.IncrementPropertyInteger.ID).TypedValue.DisplayValue != "")
                                        {
                                            PropertyValues properties = new PropertyValues();
    
                                            properties.Add(-1, newObject.createPropertyValueLookup(39, this.Configuration.POTimeLoop.POTimeLoop1Settings.EndWorkflowAndState.State.ID));
    
                                            int incrementValue = Int32.Parse(objectToLoop.GetProperty(this.Configuration.POTimeLoop.POTimeLoop1Settings.IncrementPropertyInteger.ID).TypedValue.DisplayValue);
                                            incrementValue++;
                                            properties.Add(-1, newObject.createPropertyValueInt(this.Configuration.POTimeLoop.POTimeLoop1Settings.IncrementPropertyInteger.ID, incrementValue));
                                            objectToLoop.SaveProperties(properties);
                                        }
                                        //if the increment is empty set it to 0 and change the state
                                        else
                                        {
                                            PropertyValues properties = new PropertyValues();
    
                                            properties.Add(-1, newObject.createPropertyValueLookup(39, this.Configuration.POTimeLoop.POTimeLoop1Settings.EndWorkflowAndState.State.ID));
    
                                            properties.Add(-1, newObject.createPropertyValueInt(this.Configuration.POTimeLoop.POTimeLoop1Settings.IncrementPropertyInteger.ID, 1));
                                            objectToLoop.SaveProperties(properties);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    //this sends a message to the dashboard saying the operation is complete
                    job.Commit((transactionalVault) =>
                    {
                    });
                    //job.Update
                    //(
                    //    percentComplete: 100,
                    //    details: $"Completed"
                    //);
                }
            }

  • This reply was deleted.
  • There's a lot to process here...  I was confused by the commented out code to start (e.g. the connection to the vault)...

    My gut instinct is that the job isn't completing successfully due to a timeout or similar.  I would suggest that you move to using an unsafe transaction processor, then update the objects one-by-one inside a transaction using the transaction runner.  You also need to add some logging (if using the VAF Extensions) and job update calls.

    Something like this, perhaps (COMPLETELY UNTESTED; I DIDN'T EVEN HAVE VISUAL STUDIO OPEN SO THERE MAY BE SOME TYPOS):

    [TaskProcessor(QueueId, POTimeLoopApp2, TransactionMode = TransactionMode.Unsafe)]
    public void POTimeLoop2(ITaskProcessingJob<TaskDirective> job)
    {	
    	// Sanity.
    	int classID = this.Configuration?.POTimeLoop?.POTimeLoop2Settings?.ClassToRunOn?.ID ?? -1;
    	int startStateID = this.Configuration?.POTimeLoop?.POTimeLoop2Settings?.StartWorkflowAndState?.State?.ID ?? -1;
    	int endStateID = this.Configuration?.POTimeLoop?.POTimeLoop2Settings?.StartWorkflowAndState?.State?.ID ?? -1;
    	int incrementProperty = this.Configuration?.POTimeLoop?.POTimeLoop2Settings?.IncrementPropertyInteger?.ID ?? -1;
    	if (!this.Configuration.POTimeLoop.POTimeLoop2Settings.Enabled)
    	{
    		this.Logger?.Info($"Skipped because task is disabled.");
    		job.Update(details: $"Skipped because task is disabled.");
    		return;
    	}
    	if(classID == -1
    		|| startStateID == -1
    		|| endStateID == -1)
    	{
    		this.Logger?.Warn($"Skipped because config invalid.");
    		job.Update(details: $"Skipped because config invalid.");
    		return;
    	}
    	
    	// Skip days we don't want to do.
    	{
    		string today = System.DateTime.Now.ToString("dddd");
    		if ((today == "Saturday" || today == "Sunday" || today == "Samedi" || today == "Dimanche") && this.Configuration.POTimeLoop.POTimeLoop2Settings.SkipWeekends)
    		{
    			// Skip.
    			this.Logger?.Info($"Skipped because it's a weekend and config says to skip weekends.");
    			job.Update(details: $"Skipped because it's a weekend and config says to skip weekends.");
    			return;
    		}
    	}
    	
    	// Search for the objects.
    	MFSearchBuilder poTimeLoopSearch = new MFSearchBuilder(transactionalVault);
    	poTimeLoopSearch.Deleted(false);
    	poTimeLoopSearch.Class(this.Configuration.POTimeLoop.POTimeLoop2Settings.ClassToRunOn.ID);
    	poTimeLoopSearch.Property(39, MFDataType.MFDatatypeLookup, this.Configuration.POTimeLoop.POTimeLoop2Settings.StartWorkflowAndState.State.ID);
    	var results = poTimeLoopSearch.Find();
    	
    	// Get the transaction runner.
    	var transactionRunner = this.GetTransactionRunner();
    	
    	// Iterate over them and update one by one in a transaction.
    	this.Logger.Debug($"There were {results.Count} items returned.");
    	job.Update(percentComplete: 0, details: $"There were {results.Count} items returned.");
    	for (int i = 1; i <= results.Count; i++)
    	{
    		transactionRunner.Run((transactionalVault) =>
    		{
    			ObjVerEx objectToLoop;
    			try
    			{
    				// Attempt to load the object.
    				this.Logger.Trace($"Processing {results[i].ObjVer}.");
    				objectToLoop = new ObjVerEx(transactionalVault, results[i].ObjVer);
    				this.Logger.Debug($"Processing {objectToLoop}.");
    				job.Update(percentComplete: (i-1) * 100 / results.Count, details: $"Processing {objectToLoop}.");
    
    				PropertyValues properties = new PropertyValues();
    				
    				// WHAT IS NEWOBJECT?!
    				var propertyValue = newObject.createPropertyValueInt(this.Configuration.POTimeLoop.POTimeLoop2Settings.IncrementPropertyInteger.ID, 1);
    				
    				//if the increment is not empty, increase it by 1 and change the state
    				if (objectToLoop.GetProperty(this.Configuration.POTimeLoop.POTimeLoop2Settings.IncrementPropertyInteger.ID).TypedValue.DisplayValue != "")
    				{
    					int incrementValue = Int32.Parse(objectToLoop.GetProperty(this.Configuration.POTimeLoop.POTimeLoop2Settings.IncrementPropertyInteger.ID).TypedValue.DisplayValue);
    					incrementValue++;
    					propertyValue.Value.SetValue(MFDatatype.MFDatatype.Integer, incrementValue);
    				}
    				
    				// Set the properties and update the object.
    				properties.Add(-1, propertyValue);
    				properties.Add(-1, newObject.createPropertyValueLookup(39, this.Configuration.POTimeLoop.POTimeLoop2Settings.EndWorkflowAndState.State.ID));
    				objectToLoop.SaveProperties(properties);
    			}
    			catch(Exception e)
    			{
    				this.Logger.Error(e, $"Could not process object {objectToLoop}.");
    				job.Update(details: $"Failed to process {objectToLoop}: {e.Message}");
    			}
    		}
    	}
    }

    You may also be able to clean up some of that configuration too (e.g. use a search conditions editor rather than hard-coding the filter logic), but I've not looked at that properly.

  • Hey Craig,

    I've had to comment out the logger pieces as we have had complications updating to the newest versions of the VAF.Extensions but my main issue after fixing some things is that your code doesn't seem to provide a reference to transactional vault? How do I resolve this?

  • In this scenario you would use the "env.Vault" (non-transactional vault reference) for reading.

  • How does one get env when env is not passed into a TaskProcessor?

    I did resolve the reference to the transactionalVault but I am not really sure what will happen until I run it:

  • Sorry, I apologise.  The job has a vault reference: job.Vault.

    I should acknowledge to myself that I cannot reply to posts as well as doing other things.  The job vault reference for an unsafe transaction processor is a non-transactional vault reference.