With the continued advancement of integrated software solutions, there has also been a need to address legacy business processes and how they may be implemented in a modern framework. These business processes tend to lean heavily on collecting large amounts of raw data from disparate sources and aggregating it together for further processing.
We were approached by a company whose business process required the aggregation of millions of data records into invoices to then be sent off for clients in a week span but relatively low system usage at all other times. This presented the challenge of aggregation processes exceeding typical processing requirements and disrupting the user experience.
To overcome this challenge, we developed an intermediary service that would take an initial request from an Acumatica user page and split its data aggregation over multiple threads each one making requests to the instance via the Contract API in a separate user session.
The implementation of multi-threading allowed for full utilization of system resources during data aggregation showing a dramatic increase in performance. To demonstrate this we created a series of 500 journal entries within an instance utilizing a series of thread counts.
The results of our small scale test cases can be seen below.
There are a number of items to note from the results, as can be seen splitting the task at hand into multiple concurrent processes. As expected, this increased performance but it’s an inherent nonlinear gain in creating or reusing threads. The number of threads should be limited in relation to the processors available to the instance reserving additional threads for session management and system processing.
(X cores * 2 threads per core) – 2 ‘Reserved threads’ = Total Processing Threads Available
When developing a system that interacts with Acumatica in a multi-threaded manner, via the Contract API, there are certain configurations that must be taken into account.
By default the maximum number of connections that can be made by a ServicePoint object is 2 and additional requests will languish on the queue until previous requests have completed. Therefore, this value should be set to the maximum number of threads determined for processing to allow maximum throughput of Contract API requests.
System.Net.ServicePointManager.DefaultConnectionLimit = X
“The ConnectionLimit property sets the maximum number of connections that the ServicePoint object can make to an Internet resource.”
If your service is written as a WCF Application be mindful that ChannelFactory<TChannel> incurs overhead during creation of communication channels and has the following behavior by default.
“To help minimize this overhead, WCF can cache channel factories when you are using a WCF client proxy. ”
In practical terms, this means that by default, there are requests from separate threads. However, the threads within the same application pool will share a established session to the Acumatica instance, this behavior can be modified to allow for a true creation of independent sessions with the following code.
ClientBase<Acumatica.DefaultSoap>.CacheSetting = CacheSetting.AlwaysOff;
When utilizing the Acumatica Contract API, the default SOAP client that is generated should be implemented within a class that manages your API specific methods. This class should implement the IDisposable method making sure to log out of the current user session before object disposal. If this is not implemented correctly, additional requests performed in other threads may exceed the concurrent user sessions available as configured within the Acumatica instance causing integration failure on future requests.
When making multiple requests to Acumatica via the Contract API, limiting the data returned to only that which is absolutely necessary can greatly increase overall system performance. The records returned can be configured with the ‘ReturnBehavior’ Property on each requests.
[From the Acumatica ERP User Guide, 6.10.0956, ReturnBehavior Property pageid=7b6ecfb4-faf6-4125-a4ae-a23a57662f3f]
To demonstrate the time difference these return behaviors made, we created 267 SOOrder records within an instance and then made calls to the system with each of the specified behaviors, limiting fields returned to 7 for the appropriate calls.
The results of our small scale test cases can be seen below.
The largest decreases in time can be seen by limiting the return of unnecessary child records. Though more modest gains were seen by limiting fields retrieved such decreases make a large difference when scale is taken into account as seen in the following table.
With the need in the industry to process increasingly large amounts of data in a short amount of time, Acumatica has shown the capabilities available through its Contract API and supporting technologies to handle a wide range of client use cases.
Joshua is an Acumatica Developer MVP and the Lead Software engineer of Accounting System Integrators, a results oriented provider of world-class software products and consulting services. He leads the development team, which built NonProfitPlus — a business management software engineered with Non-Profit organizations in mind and powered by Acumatica ERP, delivering a suite of fully integrated applications. As a developer who has worked with the Acumatica framework through years of its growth and refinement Joshua has cultivated a deep knowledge of the framework and those systems that may interact with it which has allowed proposals of innovative solutions to overcome challenging client requirements. An active member of Stackoverflow.com as he encourages fellow developers to share their questions and help one another out in the hopes of building a solid knowledge base for a solid framework. In his free time, Joshua enjoys being involved in his local community as well as politics having run for public office in his “spare” time.
Our promise to you:
1. We will never give your e-mail address to anyone else for any reason.
2. You can opt-out at any time.
Signing up for newsletters indicates you agree with our terms of service
If you decide that you no longer want to receive a newsletter, you can unsubscribe by clicking the "Unsubscribe" link, located at the bottom of each newsletter.