Friday, March 24, 2023
HomeJavascriptUtilizing A Closure To Encapsulate CFThread Execution And Error Dealing with In...

Utilizing A Closure To Encapsulate CFThread Execution And Error Dealing with In ColdFusion


In ColdFusion, I am a large fan of utilizing Closures to create a clear separation of issues between the enterprise logic and the low-level mechanics required to execute a given algorithm. I’ve used closures for issues like managing temp directories, pulling sources out of a connection pool, and implementing distributed locks. And, in relation to executing CFThread tags, I nearly all the time break up my asynchronous code from my enterprise logic. Nevertheless, it wasn’t till the opposite day that it occurred to me that I may in all probability use Closures to simplify the execution of asynchronous CFThread tags in ColdFusion.

The fundamental thought behind utilizing a ColdFusion Closure to create a separation of issues is that you just go the closure out of scope and into one other operate. This different operate then handles the low-level, non-business-logic code and invokes the passed-in closure as a part of the execution. The sample seems one thing like this (pseudo-code):

<cfscript>

	runMyClosure(
		() => {

			// The enterprise logic right here inside my closure.

		}
	);

	// ---
	// The low-level mechanics are dealt with right here on this different methodology.
	// ---

	non-public void operate runMyClosure( required operate operator ) {

		// Low-level mechanics right here.
		// Low-level mechanics right here.

		operator(); // Execute the passed-in operator.

		// Low-level mechanics right here.
		// Low-level mechanics right here.

	}

</cfscript>

Usually, when utilizing this system, I am executing synchronous code, like file I/O; and, the closure is admittedly simply there to separate the logic from the mechanics. A decade in the past, when ColdFusion 10 got here out, I did a whole lot of experimenting with passing closures right into a CFThread tag; nevertheless, till now, it by no means occurred to me that I’d use closures to utterly encapsulate the CFThraed tag logic itself.

To discover this concept, I’ve created a mock ColdFusion element for creating customers. It has one public methodology, createUser(), that should carry out some asynchronous logging as a part of its workflow. This logging goes to be outlined inside a ColdFusion closure which will probably be invoked inside an asynchronous CFThread tag. Nevertheless, the CFThread mechanics will probably be encapsulated inside their very own methodology, runSafelyInThread().

element
	output = false
	trace = "I present service strategies for customers."
	{

	/**
	* I create a person document with the given credentials.
	*/
	public numeric operate createUser(
		required string e mail,
		required string password
		) {

		var person = {
			id: randRange( 1, 999999 ),
			e mail: e mail,
			password: password,
			createdAt: now()
		};

		// The given closure will probably be executed inside a CFThread physique. Any errors that
		// happen in the course of the spawning / execution will probably be safely caught and logged.
		runSafelyInThread(
			() => {

				cfdump( var = "Consumer [#user.id#] created.", output = "console" );

			}
		);

		return( person.id );

	}

	// ---
	// PRIVATE METHODS.
	// ---

	/**
	* I encapsulate the asynchronous spawning and execution of the given operator.
	* 
	* In terms of operating code asynchronously inside a CFThread tag, there are two
	* issues that may go flawed: first, the JVM is likely to be out of threads (very uncommon) and
	* cannot really spawn a brand new thread so that you can run. And second, as soon as the thread has
	* been spawned and is operating, the code executing contained in the CFThread physique would possibly throw
	* an error that's misplaced into the ether. To encapsulate the error dealing with, all of the
	* enterprise logic will probably be contained contained in the passed-in Operator; and, the entire low-
	* stage mechanics of safely operating a thread will probably be dealt with inside this methodology.
	* --
	* NOTE: There may be additionally the potential of "sudden thread dying"; however, I do not consider
	* we will deal with that kind of error right here.
	*/
	non-public void operate runSafelyInThread( required operate operator ) {

		attempt {

			thread
				title = "UserService.runSafelyInThread.#createUuid()#"
				motion = "run"
				operator = operator
				{

				attempt {

					operator();

				} catch ( any error ) {

					logError( error, "Operator error inside runSafelyInThread operator." );

				}

			}

		// There is a tiny likelihood that the JVM is out of threads as a consequence of excessive load. Catch
		// these errors in order that the dad or mum request does not blow up.
		} catch ( any error ) {

			logError( error, "CFThread couldn't be spawned in runSafelyInThread." );

		}

	}


	/**
	* I log the given error and message to the console.
	*/
	non-public void operate logError(
		required any error,
		required string message
		) {

		cfdump( var = message, output = "console" );
		cfdump( var = error, output = "console" );

	}

}

As you may see, the runSafelyInThread() methodology takes care of error dealing with, each inside and outdoors of the CFThread tag. And, this methodology handles the execution of the passed-in ColdFusion closure as soon as the the asynchronous thread has been efficiently spawned. This enables the passed-in closure to worry-not in regards to the threading and focus solely on the logging.

Discover additionally that the closure is referencing the person object with is a part of the native scope of the lexical context!

To do that out, I created a easy take a look at web page that creates a single person:

<cfscript>

	id = new UserService()
		.createUser( "skroob@spaceballs.film", "12345" )
	;

	writeOutput( "Woot woot, #id# created." );

</cfscript>

If we run this ColdFusion code – within the newest Adobe ColdFusion or Lucee CFML – and we take a look at the logs, we get the next output:

[INFO] string Consumer [990685] created.

That is the logging that was generated by our ColdFusion closure that was handed into the CFThread tag.

Not solely did the ColdFusion closure preserve the bindings to its lexical scope after it was handed into the CFThread tag, we have been capable of create a clear separation of issues between the enterprise logic (the logging) and the low-level mechanics (the thread spawning). It is sort of astonishing how simple ColdFusion makes it to run code asynchronously.

when it blocks to the way it handles (or moderately does not deal with) errors. It’s extremely attainable that within the years since I’ve appeared on the preliminary implementation of runAsync(), all of those bumps have been smoothed out. Nevertheless, in the interim, I discover the CFThread tag a lot simpler to motive about.

Wish to use code from this put up?
Try the license.



RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments