3.0.0 • Published 4 years ago

electron-load-balancer v3.0.0

Weekly downloads
61
License
ISC
Repository
github
Last release
4 years ago

electron-load-balancer :fire:

Electron background task runner for humans :hearts:

There are three possible ways of doing heavy computation ( thread blocking jobs ) in electron environment without chocking the app

  • Web workers
  • Forking
  • Hidden renderer process :white_check_mark:

This libary lets you use the third one with very clean and easy to understand boilerplate code. Just five functions and your are golden. The need for this library came up when I was unable to find a standard approach to use the hidden renderer process technique to do some heavy lifting with electron. Why we are using the hidden renderer process in the first place is yet another topic for discussion. You can give this article a quick read if you are interested to know more.
I have kept it very minimalistic in nature, thus it will not bound you to do any kind of data communication through the libary itself. It will just do what it is supposed to do - manage hidden windows and get out of your way.
The rest is upto you.

Installation

npm install --save electron-load-balancer

Usage

There are a few things that you should probably know before using this library.

  • Every hidden window is an html file with just the script tag in it. All the JS code goes inside this script tag. Everything else is just your usual NodeJS code.
  • Each background task is predefined as you will be writing the html files for them, but the arguments can be passed dynamically.
  • A registration of each background task defined in html files need to be done at the starting, in your application entry point ( Main process ).
  • There are two use cases of the libary - one in which a task needs to be started and killed by the action of the user, second in which the task will be allowed to run its full course and will not accept any kind of interuption from user. Both of these cases have been covered.

Registration

1. register( ipcMain, registeredPaths )

Desciption: Used to populate registeredPath object, which is later used for 
	hidden window creation. This function is also responsible for setting up
	the other internal IPC listeners that handle creation and destruction of
	background workers.

Args: 
	ipcRenderer (required): The ipcRenderer being used in the visible window 
		renderer process.
	registeredPaths (required): An object with keys being the process name used
		to represent each hidden worker and value being the file path of the html
		that will be used to create the hidden window.

Returns: none

First off, you need to register all the background processes that you plan to execute in your app. The registeredPaths is an object with keys being the process name and values being the html file path. As the syntax shows, you'll need to pass the ipcMain object as the first argument. Here is a quick example.

// in main.js
const { ipcMain } = require('electron');
const loadBalancer = require('electron-load-balancer');

.
.
.
.

loadBalancer.register(
	ipcMain,
	{
		'oscilloscope': '/src/linkers/oscilloscope.html',
		'logicAnalyser': 'src/linkers/logicAnalyser.html',
	}
)

Note: The file path should be derived from the project root. Here is my file structure for more clarity.

|--node_modules
|
|--src
|	|
|	|--main.js
| |
| linkers
|		|
|		|--oscilloscope.html
|		|--logicAnalyser.html

Start / Stop background process from visible window

2. startBackgroundProcess( ipcRenderer, processName, values )

Desciption: Sends an IPC message to main process to create a hidden window for
	background processing. The html file matching the processName key used during 
	registration will be created.

Args: 
	ipcRenderer (required): The ipcRenderer being used in the visible window 
		renderer process.
	processName (required): The name of the process matching the one used 
		during registration of html file.
	values (optional): The initialization values that may be required for the
		background process.

Returns: none

This function is used to tell the library to start initializing the background process. The processName mentioned as the second argument must match exactly to one of the processes mentioned during registration.
The third argument lets you pass any extra data that your background process may need to get started.
The first argument will the the ipcRenderer object that will be imported in the renderer process.
Here is a quick example on how to use it assuming I wish to call it from a react component on a button click.

// in App.js
import React, { Component } from 'react';
.
.
const electron = window.require('electron');
const ipcRenderer = electron.ipcRenderer;
const loadBalancer = window.require('electron-load-balancer');

.
.
.

class App extends Component {

	.
	.
	.

	onClick = () => {
		loadBalancer.startBackgroundProcess( ipcRenderer ,'oscilloscope');
	}

	.
	.
	.
}

export default App

3. stopBackgroundProcess( ipcRenderer, processName )

Desciption: Sends an IPC message to main process to stop an already running
	background process. The hidden window matching the processName key used 
	during registration will be destroyed.

Args: 
	ipcRenderer (required): The ipcRenderer being used in the visible window 
		renderer process.
	processName (required): The name of the process matching the one used 
		during registration of html file.

Returns: none

This function is used to tell the library to stop and destroy the background process. The processName mentioned as the second argument must match exactly to one of the processes mentioned during registration.
The first argument will the the ipcRenderer object that will be imported in the renderer process. This is used only when the user is actually allowed to intervene in the background process. Here is a quick example on how to use it assuming I wish to call it from a react component on a button click.

// in App.js
import React, { Component } from 'react';
.
.
const electron = window.require('electron');
const ipcRenderer = electron.ipcRenderer;
const loadBalancer = window.require('electron-load-balancer');

.
.
.

class App extends Component {

	.
	.
	.

	onClick = () => {
		loadBalancer.stopBackgroundProcess( ipcRenderer ,'oscilloscope');
	}

	.
	.
	.
}

Initilization / Kill hook in hidden renderer process

4. onInitialize( ipcRenderer, processName, func )

Desciption: Sends an IPC message to main process letting it know that the hidden
	window has been successfully created and the blocking process can now be 
	safely started. This also takes care of passing the initilization values 
	that may be needed for the background process.

Args: 
	ipcRenderer (required): The ipcRenderer being used in the hidden window 
		renderer process.
	processName (required): The name of the process matching the one used 
		during registration of the current html file.
	func (required): The fuction that when exectued will create a heavy blocking
		process.

Returns: none

This function is used to notify the main process about the successful creation of hidden window. After this, the main process sends the initialization values that may be required for the background process to start.
The processName must match the one provided during registration for this particular html file.
The third argument is the function which when executed shall start the blocking process. The argument of this function will be the initialization value that the user may have provided. Here is a quick example on how to use it.

// in oscilloscope.js
<script>
	const { ipcRenderer } = require('electron');
	const loadBalancer = require('electron-load-balancer');
	
	loadBalancer.onInitialize(ipcRenderer, 'oscilloscope', initialValues => {
		
		/* -------------------- Blocking code here ----------------------- */

		.
		.
		.

		/* --------------------------------------------------------------- */
	
	});

</script>

5. onFinish( ipcRenderer, processName, func )

Desciption: A hook that is placed inside the computation function, which is
	used to terminate the blocking process on request from the visible renderer
	process. This is the place for killing the blocking thread and clean up work.

Args: 
	ipcRenderer (required): The ipcRenderer being used in the hidden window 
		renderer process.
	processName (required): The name of the process matching the one used 
		during registration of the current html file.
	func (optional): The fuction that when exectued just before the process is
		killed. The place to do cleanup work.

Returns: none

This function comes in handy when the user is allowed to kill the process at will. When the user triggers the stopBackgroundProcess function, this hook is triggered and the function passed as the third argument is executed, which can be used to kill the process. The destruction of the hidden window will be handled by the library itself. Here is a little example with a while loop being the blocking process which can be terminated by changing the value of variable. Important thing to note here is the the hook is placed within the fucntion passed to the onInitialize hook.

// in oscilloscope.js
<script>
	const { ipcRenderer } = require('electron');
	const loadBalancer = require('electron-load-balancer');
	
	loadBalancer.initialize(ipcRenderer, 'oscilloscope', initialValues => {
		
		/* -------------------- Blocking code here ----------------------- */

		let x = true;

		loadBalancer.onFinish(ipcRenderer, 'oscilloscope', () => {
			x = false;
		});

		while( x ){
			console.log( 'Loop running' );
		}

		/* --------------------------------------------------------------- */
	
	});

</script>

6. finish( ipcRenderer, processName )

Desciption: If the process is a heavy computation that eventually dies out on
	its own and does not require a remote tigger to be killed, then this funtion
	is used to notify the load-balancer about the finished job so that it can
	kill the hidden process. It is somewhat of a manual trigger.

Args: 
	ipcRenderer (required): The ipcRenderer being used in the hidden window 
		renderer process.
	processName (required): The name of the process matching the one used 
		during registration of the current html file.

Returns: none

This function is optional and needs to be used if we don't use the kill hook which would mean that the user is not allowed to interupt the process once started. This function is necessary in that case as we will still need to let the library know that the task has been completed.
Here is an example demonstrating a while loop that is blocking the thread but will release it eventually on its own.

// in oscilloscope.js
<script>
	const { ipcRenderer } = require('electron');
	const loadBalancer = require('electron-load-balancer');
	
	loadBalancer.initialize(ipcRenderer, 'oscilloscope', initialValues => {
		
		/* -------------------- Blocking code here ----------------------- */

		let x = 100000000;

		while( x-- ){
			console.log( 'Loop running' );
		}
		
		/* --------------------------------------------------------------- */
	
		loadBalancer.finish(ipcRenderer, 'oscilloscope');
	});

</script>

How it works

As a picture is worth a thousand words, here is a simple flow diagram of my architecture which is pretty primitive to be honest, but hey, it works!! :wink:

Contribution guidelines for this project

3.0.0

4 years ago

2.0.0

5 years ago

1.0.9

5 years ago

1.0.8

5 years ago

1.0.7

5 years ago

1.0.6

5 years ago

1.0.5

5 years ago

1.0.4

5 years ago

1.0.3

5 years ago

1.0.2

5 years ago

1.0.1

5 years ago

1.0.0

5 years ago