Automation and performance have been the most crucial cogs in the software quality wheel since the turn of the century, especially over the last ten years. As a result, automation and performance have dominated the spectrum, although more conventional software testing disciplines like functional and system testing have received some attention.
Until a decade ago, the main indicator of software quality was its accuracy, where users were generally satisfied with the software’s functionality. However, users now have much higher expectations. From the end user’s perspective, performance entails that the software operates properly and promptly reacts to user input.
Knowing that an application’s efficiency and performance are crucial, we will discuss two tools—web workers and database connection pooling—that enhance its effectiveness in their own domains. So let us get started.
What is a Web Worker?
Web Workers are multithreaded objects that run several JavaScript scripts concurrently without degrading the application’s or website’s functionality. It does this by enabling scripts to run for extended periods without being interrupted by the scripts that react to user input, such as clicks or other interactions, maintaining the page’s responsiveness. Web Workers are relatively large and not meant to be used frequently. For example, launching one worker for every pixel for a four-megapixel image would be inappropriate.
How does a Web Worker Work?
Web Workers are initialised with the URL of a JavaScript file, which the worker will execute. This code communicates with the script that spawned it from the home page and sets event listeners. The straightforward syntax is as follows:
var worker = new Worker(‘workerfile.js’);
The Worker API interface allows a thread to be created in the background, and a <worker file.js> file must be passed as a parameter to the worker file to tell the API that needs to be executed. The browser will start a new worker thread for the asynchronous download if the requested javascript file is already present. Otherwise, a 404 error will be returned if the path to your worker is not present, and the worker will fail silently. Following spawning, postMessage() is used to establish communication between the web worker and its parent. page.postMessage() can take a string or a JSON object as its single argument, depending on your browser/version.
With the help of the ‘onmessage’ event on the main page, the message passed by the web worker is accessed. Now, we use Web Worker to create our <workerfile.js> example by creating the main page (hello.html). This page will launch a web worker to run the loop and return the variable j’s final value, as shown below:
<!DOCTYPE HTML>
<html>
<head>
<title>Big for loop</title>
<script>
var worker = new Worker(‘workerfile.js’);
worker.onmessage = function (event) {
alert(“Completed “ + event.data + “iterations”);
};
function sayHello() {
alert(“Hello world!”);
}
</script>
</head>
<body>
<input type = “button” onclick = “sayHello();” value = “Say Hello”/>
</body>
</html>
The following is the workerfile.js file’s content. It uses the postMessage() API to send the communication back to the main page:
for (var i = 0; i <= 1000000000; i += 1) {
var j = i;
}
postMessage(j);
After using the web worker, we need to terminate it as it will continue to run if not stopped. Therefore, the page needs to call the terminate() method like:
worker.terminate();
A Web Worker that has been terminated will no longer process new computations or reply to messages. A worker cannot be restarted; however, a new worker may be created using the same URL.
What is Database Connection Pooling?
In a web application, when a user requests data from a database, a connection is made to access a backend service, which uses OS resources to establish, maintain, and close connections to the datastore. Relational database servers like Postgres or MySQL power most web services. For example, each new connection in PostgreSQL can consume up to 1.3MB of memory. It can quickly exhaust your memory resources in a production environment where we expect numerous concurrent connections to the backend service. Therefore, a large amount of overhead causes database performance to deteriorate.
Database connection pooling comes into play here. Instead of opening and closing connections for each request, it uses a cache of database connections that can be used again when additional database requests are necessary. It allows your database to scale effectively as the amount of data stored and clients accessing it grows. In addition, because traffic is never constant, pooling allows for better traffic management without causing outages. In return, we save resources by not having to open and close a new connection each time the database performs the query.
How to Create Connection Pools?
First, we necessarily do not need to attempt to construct a connection pool from scratch. Effective connection pooling frameworks are already available, depending on the application language and database technology of choice, for example, for Go applications using Postgres-compatible databases, pgxpool; for Java applications, HikariCP, and many more. To get the best performance, we will still need to adjust the parameters and size of our pool. When using a connection pool, we must weigh the costs of maintaining connections versus creating/severing new ones. The number of idle connections should be kept to a minimum, but we also want to minimise the time spent opening and closing new connections. Additionally, we want to confirm that the maximum connections reflect the maximum amount of work your database can handle.
When connecting to a pool-enabled data source or building a connection pool using the connection pool manager, connection pool properties are set. Following is the example that shows setting connection pool properties through a pool-enabled data source:
PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
pds.setConnectionPoolName(“JDBC_UCP”);
pds.setMinPoolSize(4);pds.setMaxPoolSize(20);
The following example shows how to set connection pool properties when using the connection pool manager:
UniversalConnectionPoolManager mgr = UniversalConnectionPoolManagerImpl.getUniversalConnectionPoolManager();
pds.setConnectionPoolName(“JDBC_UCP”);
pds.setMinPoolSize(4);pds.setMaxPoolSize(20);
…
mgr.createConnectionPool(pds);
Advantages of Web Workers
Web workers make concurrency easier and enable parallelism, or tasks running truly concurrently without necessarily blocking one another or the user interface. Before web workers, you had to micro-manage long javascript-based running tasks in your browser to break them into manageable chunks and keep the UI responsive. Additionally, it was more complicated to have multiple ongoing tasks.
Advantages of Connection Pooling
On the other hand, a connection pool provides various advantages. For example, it reduces the number of times new connection objects are created, reuses connection objects, accelerates the process of establishing a connection, reduces the amount of effort required to manage connection objects manually, reduces the number of close connections, and controls the number of resources used to maintain connections.
Wrapping Up
As we all know, it is critical to constantly improve the application’s user experience; one of the most important factors contributing to this is performance, as established above. To conclude, these tools can significantly increase your applications’ speed and provide your users with the best possible experience, allowing your product to compete in the market.