als-file-handler
The FileHandler
class is a sophisticated tool designed to manage and coordinate asynchronous file operations in Node.js applications. This class efficiently handles scenarios where multiple asynchronous tasks need to interact with the same file, ensuring that these interactions are executed sequentially to avoid conflicts and data corruption.
-
Purpose
: FileHandler is designed for streamlined, concurrent-safe file operations, ensuring error-resistant reading, writing, and deleting of files. -
Queueing File Operations
: It queues operations on the same file, executing them sequentially to prevent race conditions and file corruption. -
Error Handling and Retries
: The class robustly handles errors, allowing for a specified number of retry attempts, ideal for addressing temporary issues like file lock contention. -
Custom Error Handling
: FileHandler supports custom error functions for each operation, providing flexible, context-specific error management. -
Configurable Wait Time, Timeout and Attempts
: It offers configurable wait times, timeout for operation and retry attempts, adapting to various operational needs and environments.
Install and require
npm i als-file-handler
const FileHandler = require('als-file-handler')
Method: add
The add
method of the FileHandler
class is used to enqueue a file operation. It accepts an object with various parameters to configure the operation. Each parameter undergoes validation to ensure correct operation and behavior.
Parameters
-
path (String):
- Purpose: Specifies the path of the file to be operated on.
- Validation: Checked to ensure it is a string and is required.
- Default Value: No default value; must be provided by the user.
-
action (Function):
- Purpose: The asynchronous function representing the file operation (e.g., read, write, delete).
- Validation: Ensures that it is a function and is required.
- Default Value: No default value; must be defined by the user.
-
attempts (Number):
- Purpose: Defines the number of retry attempts for the operation in case of failure.
- Validation: Verified to be a number.
-
Default Value: Inherits from
FileHandler.attempts
, which is3
by default. Can be overridden by specifying a different value.
-
errorFn (Function):
- Purpose: A custom error handling function that is called when an operation fails after all retry attempts.
- Validation: Checked to ensure it is a function.
-
Default Value: Inherits from
FileHandler.errorFn
, which defaults to a function returning the error. It can be overridden by providing a custom function.
-
waitTime (Number):
- Purpose: The time in milliseconds to wait before retrying the operation after an error.
- Validation: Verified to be a number.
-
Default Value: Inherits from
FileHandler.waitTime
, which is100
ms by default. This value can be changed by specifying a different number.
-
timeout:
- Purpose: Sets a maximum time limit for an operation to complete, after which the operation is considered failed.
- Validation: Verified to be a number (milliseconds).
- Default Value: If not specified, operations will not have a timeout. Can be set by specifying a number of milliseconds.
waitTime
andtimeout
handled with als-time-manager, which using only one setTimeout for all time tasks.
Return Value
The add
method returns a Promise that resolves with an object containing the outcome of the file operation. This Promise only has a resolve path, as it's designed to handle errors internally and return them as part of the resolution. The structure of the resolved object is as follows:
-
Object Structure:
{ result, error }
-
result
: The result of the successful file operation ornull
if the operation fails or encounters an error. -
error
: An error object if the operation fails, ornull
if the operation is successful.
-
When an operation is cancelled due to a timeout, the Promise resolves with an error object indicating the timeout:
-
Timeout Error:
- If an operation exceeds the specified timeout, the Promise resolves with
{ result: null, error: [TimeoutErrorObject] }
.
- If an operation exceeds the specified timeout, the Promise resolves with
Possible Outcomes
-
Successful Operation:
- The operation completes successfully.
- The Promise resolves with
{ result: [OperationResult], error: null }
. -
[OperationResult]
represents the successful result of the file operation.
-
Failed Operation:
- The operation fails after the specified number of attempts.
- The Promise resolves with
{ result: null, error: [ErrorObject] }
. -
[ErrorObject]
containsdetails
of the error that occurred during the operation: -
path
: The file path where the operation was attempted. -
attempts
: The number of attempts made to perform the operation before failing.
Usage
Here is an example of how to use the add
method:
const {result,error} = await FileHandler.add({
path: '/path/to/file.txt',
action: async () => { /* file operation logic */ },
attempts: 5,
errorFn: (error) => console.error('Custom Error:', error),
waitTime: 200,
timeout: 5000 // 5 seconds timeout
});
Example
const {writeFile} = require('fs/promises')
const FileHandler = require('als-file-handler')
const action = async () => await writeFile(path, 'Hello')
const path = 'some.txt'
const {result:content,error} = await FileHandler.add({ path, action })
Parent Directory Check
Parent Directory Check:
- Functionality: Ensures that operations on a file or directory wait for any pending operations on its parent directory to complete, maintaining the integrity of file operations in nested structures.
-
Implementation: Automatically managed by
FileHandler
; no additional parameters required. The class internally checks and queues operations based on their file paths to respect directory hierarchies.
const {writeFile, mkdir} = require('fs/promises');
const FileHandler = require('als-file-handler');
// Creating a parent directory
const parentDir = 'parentDir';
const childFile = 'parentDir/childFile.txt';
// Operation on the parent directory
FileHandler.add({ path: parentDir, action: async () => await mkdir(parentDir) });
// Operation on a file inside the parent directory
const {result, error} = await FileHandler.add({ path: childFile, action: async () => await writeFile(childFile, 'Hello') });