|
1 | 1 | -- | Bindings to the global `process` object in Node.js. See also [the Node API documentation](https://nodejs.org/api/process.html)
|
2 | 2 | module Node.Process
|
3 |
| - ( onBeforeExit |
4 |
| - , onExit |
5 |
| - , onSignal |
6 |
| - , onUncaughtException |
7 |
| - , onUnhandledRejection |
| 3 | + ( Process |
| 4 | + , process |
| 5 | + , beforeExitH |
| 6 | + , disconnectH |
| 7 | + , exitH |
| 8 | + , messageH |
| 9 | + , rejectionHandledH |
| 10 | + , uncaughtExceptionH |
| 11 | + , unhandledRejectionH |
| 12 | + , mkSignalH |
| 13 | + , mkSignalH' |
| 14 | + , warningH |
| 15 | + , workerH |
8 | 16 | , abort
|
9 | 17 | , argv
|
10 | 18 | , argv0
|
@@ -71,51 +79,143 @@ import Data.Nullable (Nullable, toMaybe)
|
71 | 79 | import Data.Posix (Pid)
|
72 | 80 | import Data.Posix.Signal (Signal)
|
73 | 81 | import Data.Posix.Signal as Signal
|
| 82 | +import Data.String as String |
74 | 83 | import Effect (Effect)
|
75 | 84 | import Effect.Exception (Error)
|
76 |
| -import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn4, mkEffectFn1, runEffectFn1, runEffectFn2, runEffectFn3, runEffectFn4) |
| 85 | +import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, EffectFn4, mkEffectFn1, mkEffectFn2, runEffectFn1, runEffectFn2, runEffectFn3, runEffectFn4) |
77 | 86 | import Foreign (Foreign)
|
78 | 87 | import Foreign.Object as FO
|
| 88 | +import Node.EventEmitter (EventHandle(..)) |
| 89 | +import Node.EventEmitter.UtilTypes (EventHandle0, EventHandle1, EventHandle2) |
79 | 90 | import Node.Platform (Platform)
|
80 | 91 | import Node.Platform as Platform
|
81 | 92 | import Node.Stream (Readable, Writable)
|
82 | 93 | import Prim.Row as Row
|
83 | 94 |
|
84 |
| --- | Register a callback to be performed when the event loop empties, and |
85 |
| --- | Node.js is about to exit. Asynchronous calls can be made in the callback, |
86 |
| --- | and if any are made, it will cause the process to continue a little longer. |
87 |
| -foreign import onBeforeExit :: Effect Unit -> Effect Unit |
| 95 | +foreign import data Process :: Type |
88 | 96 |
|
89 |
| --- | Register a callback to be performed when the process is about to exit. |
90 |
| --- | Any work scheduled via asynchronous calls made here will not be performed |
91 |
| --- | in time. |
| 97 | +foreign import process :: Process |
| 98 | + |
| 99 | +-- | The 'beforeExit' event is emitted when Node.js empties its event loop and has no additional work to schedule. |
| 100 | +-- | Normally, the Node.js process will exit when there is no work scheduled, but a listener registered on the |
| 101 | +-- | 'beforeExit' event can make asynchronous calls, and thereby cause the Node.js process to continue. |
| 102 | +-- | |
| 103 | +-- | The listener callback function is invoked with the value of process.exitCode passed as the only argument. |
| 104 | +-- | The 'beforeExit' event is not emitted for conditions causing explicit termination, |
| 105 | +-- | such as calling `process.exit()` or uncaught exceptions. |
| 106 | +-- | The 'beforeExit' should not be used as an alternative to the 'exit' event unless the |
| 107 | +-- | intention is to schedule additional work. |
| 108 | +beforeExitH :: EventHandle1 Process Int |
| 109 | +beforeExitH = EventHandle "beforeExit" mkEffectFn1 |
| 110 | + |
| 111 | +disconnectH :: EventHandle0 Process |
| 112 | +disconnectH = EventHandle "disconnect" identity |
| 113 | + |
| 114 | +-- | The 'exit' event is emitted when the Node.js process is about to exit as a result of either: |
| 115 | +-- | - The process.exit() method being called explicitly; |
| 116 | +-- | - The Node.js event loop no longer having any additional work to perform. |
| 117 | +-- | |
| 118 | +-- | Listener functions **must** only perform **synchronous** operations. |
| 119 | +-- | The Node.js process will exit immediately after calling the 'exit' event listeners causing |
| 120 | +-- | any additional work still queued in the event loop to be abandoned. |
| 121 | +-- | (Maintainer note: I believe the above translates to |
| 122 | +-- | "Only synchronous (i.e. `Effect`) code can be run in the resulting handler. |
| 123 | +-- | If you need asynchronous (i.e. `Aff`) code, use `beforeExitH`.") |
| 124 | +-- | |
| 125 | +-- | There is no way to prevent the exiting of the event loop at this point, and once all 'exit' |
| 126 | +-- | listeners have finished running the Node.js process will terminate. |
| 127 | +-- | The listener callback function is invoked with the exit code specified either by the |
| 128 | +-- | `process.exitCode` property, or the exitCode argument passed to the `process.exit()` method. |
| 129 | +exitH :: EventHandle1 Process Int |
| 130 | +exitH = EventHandle "exit" mkEffectFn1 |
| 131 | + |
| 132 | +messageH :: EventHandle Process (Foreign -> Maybe Foreign -> Effect Unit) (EffectFn2 Foreign (Nullable Foreign) Unit) |
| 133 | +messageH = EventHandle "message" \cb -> mkEffectFn2 \a b -> cb a (toMaybe b) |
| 134 | + |
| 135 | +-- | The 'rejectionHandled' event is emitted whenever a Promise has been rejected and an error handler was attached to it (using promise.catch(), for example) later than one turn of the Node.js event loop. |
| 136 | +-- | |
| 137 | +-- | The Promise object would have previously been emitted in an 'unhandledRejection' event, but during the course of processing gained a rejection handler. |
| 138 | +-- | |
| 139 | +-- | There is no notion of a top level for a Promise chain at which rejections can always be handled. Being inherently asynchronous in nature, a Promise rejection can be handled at a future point in time, possibly much later than the event loop turn it takes for the 'unhandledRejection' event to be emitted. |
| 140 | +-- | |
| 141 | +-- | Another way of stating this is that, unlike in synchronous code where there is an ever-growing list of unhandled exceptions, with Promises there can be a growing-and-shrinking list of unhandled rejections. |
| 142 | +-- | |
| 143 | +-- | In synchronous code, the 'uncaughtException' event is emitted when the list of unhandled exceptions grows. |
| 144 | +-- | |
| 145 | +-- | In asynchronous code, the 'unhandledRejection' event is emitted when the list of unhandled rejections grows, and the 'rejectionHandled' event is emitted when the list of unhandled rejections shrinks. |
| 146 | +rejectionHandledH :: EventHandle1 Process Foreign |
| 147 | +rejectionHandledH = EventHandle "rejectionHandled" mkEffectFn1 |
| 148 | + |
| 149 | +-- | Args: |
| 150 | +-- | - `err` <Error> The uncaught exception. |
| 151 | +-- | - `origin` <string> Indicates if the exception originates from an unhandled rejection or from a synchronous error. |
| 152 | +-- | Can either be 'uncaughtException' or 'unhandledRejection'. |
| 153 | +-- | The latter is used when an exception happens in a Promise based async context (or if a Promise is rejected) |
| 154 | +-- | and `--unhandled-rejections` flag set to `strict` or `throw` (which is the default) and |
| 155 | +-- | the rejection is not handled, or when a rejection happens during the command line entry point's |
| 156 | +-- | ES module static loading phase. |
92 | 157 | -- |
|
93 |
| --- | The argument to the callback is the exit code which the process is about |
94 |
| --- | to exit with. |
95 |
| -foreign import onExit :: (Int -> Effect Unit) -> Effect Unit |
96 |
| - |
97 |
| --- | Install a handler for uncaught exceptions. The callback will be called |
98 |
| --- | when the process emits the `uncaughtException` event. The handler |
99 |
| --- | currently does not expose the second `origin` argument from the Node 12 |
100 |
| --- | version of this event to maintain compatibility with older Node versions. |
101 |
| -foreign import onUncaughtException :: (Error -> Effect Unit) -> Effect Unit |
102 |
| - |
103 |
| --- | Install a handler for unhandled promise rejections. The callback will be |
104 |
| --- | called when the process emits the `unhandledRejection` event. |
| 158 | +-- | The 'uncaughtException' event is emitted when an uncaught JavaScript exception bubbles |
| 159 | +-- | all the way back to the event loop. By default, Node.js handles such exceptions |
| 160 | +-- | by printing the stack trace to `stderr` and exiting with code 1, |
| 161 | +-- | overriding any previously set `process.exitCode`. |
| 162 | +-- | Adding a handler for the 'uncaughtException' event overrides this default behavior. |
| 163 | +-- | Alternatively, change the process.exitCode in the 'uncaughtException' handler which will |
| 164 | +-- | result in the process exiting with the provided exit code. Otherwise, in the presence of |
| 165 | +-- | such handler the process will exit with 0. |
105 | 166 | -- |
|
106 |
| --- | The first argument to the handler can be whatever type the unhandled |
107 |
| --- | Promise yielded on rejection (typically, but not necessarily, an `Error`). |
| 167 | +-- | 'uncaughtException' is a crude mechanism for exception handling intended to be used only as a last resort. The event should not be used as an equivalent to On Error Resume Next. Unhandled exceptions inherently mean that an application is in an undefined state. Attempting to resume application code without properly recovering from the exception can cause additional unforeseen and unpredictable issues. |
| 168 | +-- | |
| 169 | +-- | Exceptions thrown from within the event handler will not be caught. Instead the process will exit with a non-zero exit code and the stack trace will be printed. This is to avoid infinite recursion. |
| 170 | +-- | |
| 171 | +-- | Attempting to resume normally after an uncaught exception can be similar to pulling out the power cord when upgrading a computer. Nine out of ten times, nothing happens. But the tenth time, the system becomes corrupted. |
| 172 | +-- | |
| 173 | +-- | The correct use of 'uncaughtException' is to perform synchronous cleanup of allocated resources (e.g. file descriptors, handles, etc) before shutting down the process. It is not safe to resume normal operation after 'uncaughtException'. |
| 174 | +-- | |
| 175 | +-- | To restart a crashed application in a more reliable way, whether 'uncaughtException' is emitted or not, an external monitor should be employed in a separate process to detect application failures and recover or restart as needed. |
| 176 | +uncaughtExceptionH :: EventHandle2 Process Error String |
| 177 | +uncaughtExceptionH = EventHandle "uncaughtException" \cb -> mkEffectFn2 \a b -> cb a b |
| 178 | + |
| 179 | +-- | Args: |
| 180 | +-- | - `reason` <Error> | <any> The object with which the promise was rejected (typically an Error object). |
| 181 | +-- | - `promise` <Promise> The rejected promise. |
108 | 182 | -- |
|
109 |
| --- | The handler currently does not expose the type of the second argument, |
110 |
| --- | which is a `Promise`, in order to allow users of this library to choose |
111 |
| --- | their own PureScript `Promise` bindings. |
112 |
| -foreign import onUnhandledRejection :: forall a b. (a -> b -> Effect Unit) -> Effect Unit |
| 183 | +-- | The 'unhandledRejection' event is emitted whenever a Promise is rejected and no error handler is attached to the promise within a turn of the event loop. When programming with Promises, exceptions are encapsulated as "rejected promises". Rejections can be caught and handled using promise.catch() and are propagated through a Promise chain. The 'unhandledRejection' event is useful for detecting and keeping track of promises that were rejected whose rejections have not yet been handled. |
| 184 | +unhandledRejectionH :: EventHandle2 Process Foreign Foreign |
| 185 | +unhandledRejectionH = EventHandle "unhandledRejection" \cb -> mkEffectFn2 \a b -> cb a b |
| 186 | + |
| 187 | +-- | Args: |
| 188 | +-- | - `warning` <Error> Key properties of the warning are: |
| 189 | +-- | - `name` <string> The name of the warning. Default: 'Warning'. |
| 190 | +-- | - `message` <string> A system-provided description of the warning. |
| 191 | +-- | - `stack` <string> A stack trace to the location in the code where the warning was issued. |
| 192 | +-- | |
| 193 | +-- | The 'warning' event is emitted whenever Node.js emits a process warning. |
| 194 | +-- | |
| 195 | +-- | A process warning is similar to an error in that it describes exceptional conditions that are being brought to the user's attention. However, warnings are not part of the normal Node.js and JavaScript error handling flow. Node.js can emit warnings whenever it detects bad coding practices that could lead to sub-optimal application performance, bugs, or security vulnerabilities. |
| 196 | +-- | By default, Node.js will print process warnings to stderr. The --no-warnings command-line option can be used to suppress the default console output but the 'warning' event will still be emitted by the process object. |
| 197 | +warningH :: EventHandle1 Process Error |
| 198 | +warningH = EventHandle "warning" mkEffectFn1 |
113 | 199 |
|
114 |
| -foreign import onSignalImpl :: String -> Effect Unit -> Effect Unit |
| 200 | +-- | Args: |
| 201 | +-- | - `worker` <Worker> The <Worker> that was created. |
| 202 | +-- | |
| 203 | +-- | The 'worker' event is emitted after a new <Worker> thread has been created. |
| 204 | +workerH :: EventHandle1 Process Foreign |
| 205 | +workerH = EventHandle "worker" mkEffectFn1 |
115 | 206 |
|
116 |
| --- | Install a handler for a particular signal. |
117 |
| -onSignal :: Signal -> Effect Unit -> Effect Unit |
118 |
| -onSignal sig = onSignalImpl (Signal.toString sig) |
| 207 | +-- | Rather than support an `EventHandle` for every possible `Signal`, |
| 208 | +-- | this function provides one a convenient way for constructing one for any given signal. |
| 209 | +-- | |
| 210 | +-- | See Node docs: https://nodejs.org/dist/latest-v18.x/docs/api/process.html#signal-events |
| 211 | +mkSignalH :: Signal -> EventHandle Process (Effect Unit) (Effect Unit) |
| 212 | +mkSignalH sig = EventHandle (Signal.toString sig) identity |
| 213 | + |
| 214 | +-- | Same as `mkSignalH` but allows for more options in case the `Signal` ADT is missing any. |
| 215 | +-- | |
| 216 | +-- | See Node docs: https://nodejs.org/dist/latest-v18.x/docs/api/process.html#signal-events |
| 217 | +mkSignalH' :: String -> EventHandle Process (Effect Unit) (Effect Unit) |
| 218 | +mkSignalH' sig = EventHandle (String.toUpper sig) identity |
119 | 219 |
|
120 | 220 | -- | The `process.abort()` method causes the Node.js process to exit immediately and generate a core file.
|
121 | 221 | -- | This feature is not available in Worker threads.
|
|
0 commit comments