PageSourceSearch

https://senecajs.org/faq/

html senecajs.org collected 2026-09-25 21:21:29 UTC 17,394 bytes, 345 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3  <head>
4    <meta charset="utf-8">
5    <meta http-equiv="X-UA-Compatible" content="chrome=1">
6    <meta name="viewport" content="width=device-width, initial-scale=1" />
7    
8    <link rel="shortcut icon" href="/images/favicon.png" type="image/png" />
9    
10    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Merriweather:400,700|Open+Sans:400,400italic,700">
11    <link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css" />
12    <link rel="stylesheet" href="/stylesheets/style.css" />
13    
14    <title>Seneca, a microservices toolkit for Node.js</title>  </head>
15  <body>
16    <nav class="nav-main" role="navigation">
17      <div class="container-fluid cf">
18        <a class="logo logo-seneca" href="/" title="Seneca">Seneca</a>
19    
20        <div class="nav-search">
21          <input type="search" id="seneca-search-input" placeholder="Search the docs...">
22        </div>
23        <!-- nav search -->
24    
25        <div class="nav-bar">
26    
27          <input type="checkbox" name="nav-menu-handle" id="nav-menu-handle" class="nav-menu-handle">
28          <label for="nav-menu-handle"></label>
29    
30          <ul class="list-unstyled list-inline nav-items">
31            <li><a href='/api/'>API</a></li>
32            <li><a href='/docs/'>Docs</a></li>
33            <li><a href='/faq/'>FAQ</a></li>
34            <li><a href='/plugins/'>Plugins</a></li>
35            <li><a href='/roadmap/'>Roadmap</a></li>
36            <li><a href='/support/'>Support</a></li>
37          </ul>
38          <!-- nav items -->
39        </div>
40    
41      </div>
42      <!-- container -->
43    </nav>
44    <header role="banner">
45      <div class="container-fluid center-xs">
46        <img src="/images/illustration-top.svg"
47             alt="Design, develop and organize code"
48             title="Design, develop and organize code"
49             height="auto"
50             width="320"
51             class="mt"
52          />
53      </div>
54    </header>
55
56    <div class="container-fluid">
57      <div class="row center-xs">
58        <div class="col-xs-12 col-md-10 col-lg-10 txt-left">
59          <h1 id="frequently-asked-questions"><a href="#frequently-asked-questions" class="linkable" style="margin-left:-2rem; margin-right:1rem; display:inline-block;font-size:1.2rem;color:rgba(41, 125, 134, 0.20);text-decoration:none;vertical-align:middle">&#xA7;</a>Frequently Asked Questions</h1>
60<ul>
61<li><a href="#q-gotq">Got a question?</a></li>
62<li><a href="#q-patuse">Why is pattern-matching so useful?</a></li>
63<li><a href="#q-recstruct">What is the recommended structure for Seneca apps?</a></li>
64<li><a href="#q-fatal">Why is the Seneca process dying with a FATAL error?</a></li>
65<li><a href="#q-reply">How do I respond to a message?</a></li>
66</ul>
67<p></p>
68
69
70
71<p><a href="#" class="linkable" style="color: rgba(41, 125, 134, 0.20); display:inline-block; float:left; margin: 8px -80px">[&#x21E7;]</a>
72<a name="q-gotq"></a></p>
73<h3 id="got-a-question"><a href="#got-a-question" class="linkable" style="margin-left:-2rem; margin-right:1rem; display:inline-block;font-size:1.2rem;color:rgba(41, 125, 134, 0.20);text-decoration:none;vertical-align:middle">&#xA7;</a>Got a question?</h3>
74<p>Please post an issue to github, marking as &#x201C;FAQ:&#x201D; in the title: <a href="https://github.com/senecajs/senecajs.org/issues/new?title=FAQ:%20">I
75want to ask a
76question!</a></p>
77<p><a href="#" class="linkable" style="color: rgba(41, 125, 134, 0.20); display:inline-block; float:left; margin: 8px -80px">[&#x21E7;]</a>
78<a name="q-patuse"></a></p>
79<h3 id="why-is-pattern-matching-so-useful"><a href="#why-is-pattern-matching-so-useful" class="linkable" style="margin-left:-2rem; margin-right:1rem; display:inline-block;font-size:1.2rem;color:rgba(41, 125, 134, 0.20);text-decoration:none;vertical-align:middle">&#xA7;</a>Why is pattern-matching so useful?</h3>
80<p>Because it gives you a clean component model. This lets you build big
81things out of small things without ending up with spaghetti code.</p>
82<p>The trick is to make composition easy. That way you can combine and
83extend microservices. Instead of modifying an existing microservice,
84simply add a new one with more functionality. This is a much more
85scalable way to handle changing requirements without building up
86technical debt.</p>
87<p>There&#x2019;s a <a href="https://vimeo.com/151465912">great talk by Gerald Sussman</a>
88(co-inventor of Scheme) on the basic principles of this idea. There&#x2019;s
89also a
90<a href="http://www.richardrodger.com/seneca-microservices-nodejs#.Vq
90i9LBiLT-k">maintainer blog post</a>
91explaining this from a Seneca perspective.</p>
92<pre style="margin-bottom:0px">
93A diamond is very pretty.
94But it is hard to add to a diamond.
95&#xA0;
96A ball of mud is not so pretty.
97But you can always add more mud to a ball of mud.
98</pre>
99<div style="text-align:right"><small>[Joel Moses](https://en.wikipedia.org/wiki/Joel_Moses) / [Paul Penfield](http://www-mtl.mit.edu/~penfield/)</small></div>
100
101<p>&#xA0;</p>
102
103
104
105<p><a href="#" class="linkable" style="color: rgba(41, 125, 134, 0.20); display:inline-block; float:left; margin: 8px -80px">[&#x21E7;]</a>
106<a name="q-recstruct"></a></p>
107<h3 id="what-is-the-recommended-structure-for-seneca-apps"><a href="#what-is-the-recommended-structure-for-seneca-apps" class="linkable" style="margin-left:-2rem; margin-right:1rem; display:inline-block;font-size:1.2rem;color:rgba(41, 125, 134, 0.20);text-decoration:none;vertical-align:middle">&#xA7;</a>What is the recommended structure for Seneca apps?</h3>
108<p>Some things that work well:</p>
109<ul>
110<li><p>Separate the business logic from the execution. Put your business
111logic into separate plugins - either separate node modules,
112different repositories, or simply different files in the same
113repository.</p>
114</li>
115<li><p>Use execution scripts to compose your app. Don&#x2019;t be afraid to use
116different scripts for different contexts. They should be pretty
117short any way. You want your scripts to look something like:</p>
118</li>
119</ul>
120<pre><code>var SOME_CONFIG = process.env.SOME_CONFIG || &apos;some-default-value&apos; 
121
122require(&apos;seneca&apos;)({ some_options: 123 })
123
124  // existing Seneca plugins
125  .use(&apos;community-plugin-0&apos;)
126  .use(&apos;community-plugin-1&apos;, {some_config: SOME_CONFIG})
127  .use(&apos;community-plugin-2&apos;)
128
129  // your own plugins with your own business logic
130  .use(&apos;project-plugin-module&apos;)
131  .use(&apos;../plugin-repository&apos;)
132  .use(&apos;./lib/local-plugin&apos;)
133
134  .listen( ... )
135  .client( ... )
136
137  .ready( function() {
138    // your own custom code - executed once Seneca is spun up
139  })</code></pre><ul>
140<li>Plugin loading order <em>is significant</em>. This is a good thing. It
141lets you control the <a href="http://www.richardrodger.com/seneca-microservices-nodejs#.VqdKAhiLT-k">composition of your message language</a>.</li>
142</ul>
143<p>Things that don&#x2019;t work well:</p>
144<ul>
145<li><p>Mixing Seneca initialization with other framework
146initialization. Define your express or hapi app in one file, and
147Seneca in another. Keep it separate and simple.</p>
148</li>
149<li><p>Passing the Seneca instance around. Don&#x2019;t create a Seneca
150instance and then pass it as a parameter to stuff you&#x2019;ve
151<code>required</code> in, and only then start adding plugins and
152actions. Instead, use small execution scripts with clear and
153linear construction of your service from a list of plugins.</p>
154</li>
155</ul>
156<p>Looking for an example structure to copy? The
157<a href="https://github.com/nodezoo/nodezoo-workshop">nodezoo workshop</a> is a good
158place to find one.</p>
159<p><a href="#" class="linkable" style="color: rgba(41, 125, 134, 0.20); display:inline-block; float:left; margin: 8px -80px">[&#x21E7;]</a>
160<a name="q-fatal"></a></p>
161<h3 id="why-is-the-seneca-process-dying-with-a-fatal-error"><a href="#why-is-the-seneca-process-dying-with-a-fatal-error" class="linkable" style="margin-left:-2rem; margin-right:1rem; display:inline-block;font-size:1.2rem;color:rgba(41, 125, 134, 0.20);text-decoration:none;vertical-align:middle">&#xA7;</a>Why is the Seneca process dying with a FATAL error?</h3>
162<p>Your Seneca microservice will rely on a set of plugins, both <a href="https://github.com/senecajs?utf8=%E2%9C%93&amp;q=seneca-*&amp;type=source&amp;language=">community
163plugins</a>, and your own, to provide the actions that respond to
164messages. All of the plugins need to load and initialize
165successfully. If they don&#x2019;t, your microservice will be in an
166undefined state. The best thing to do in this case is bail out and
167die.</p>
168<p>For example, if you are using the
169<a href="https://github.com/senecajs/seneca-mongo-store"><code>seneca-mongo-store</code></a>
170plugin, and the plugin cannot connect to the database, then your
171microservice can&#x2019;t do any work. Maybe the failure is transient. In
172that case, you want the microservice to die and restart. Your
173container system (Docker, Kubernetes, etc) will start a new instance
174of your microservice, but needs the old one to die first.</p>
175<p>When
176<a href="/docs/tutorials/how-to-write-a-plugin.html">Seneca loads a plugin</a>,
177it is first <em>defined</em>, then <em>initialized</em>. Plugin definition happens
178inside the plugin definition function, where you add your patterns:</p>
179<pre><code class="language-js">// file: foo.js
180// The string `foo` will be the name of the plugin.
181module.exports = function foo(options) {
182
183  // `this` === context Seneca instance with fatal$ === true
184  // the pattern is `a:1`
185  this.add(&apos;a:1&apos;, function (msg, reply) {
186    reply({x: msg.x})
187  }) 
188}</code></pre>
189<p>A failure of any sort here is fatal, as it means the plugin is not
190fully defined. Some patterns could be missing. Plugin definition is
191<em>synchronous</em>
191.</p>
192<p>Plugin initialization happens inside the <code>init:&lt;plugin-name&gt;</code>
193action. Add this inside your plugin definition:</p>
194<pre><code class="language-js">// file: foo.js
195// The function `foo` will be the name of the plugin.
196module.exports = function foo(options) {
197
198  this.add(&apos;a:1&apos;, function (msg, reply) {
199    reply({x: msg.x})
200  }) 
201
202  this.add(&apos;init:foo&apos;, function (msg, reply) {
203
204    // do something asynchronous
205    database_setup(options, function(err) {
206
207      // call reply to indicate that the plugin is initialized,
208      // no need for response data
209      reply(err)
210    })
211  })
212}</code></pre>
213<p>Plugin initialization is optional, and only necessary if you need to
214perform an asynchronous operation such as interacting with the outside
215world. Failures in initialization are also fatal.</p>
216<p>The <a href="/api/#method-ready"><code>seneca.ready</code></a> callback is not called until
217all plugins are defined and initialized.</p>
218<p>To make an action fatal when it fails, use the <code>fatal$:true</code> directive
219as part of your message. This is what Seneca itself does for plugin
220definition (which is run inside an internally created one-off action)
221and initialization. The <code>fatal$</code> directive is set as a fixed argument
222of any messages sent by the plugin Seneca context.</p>
223<p>There are times when you want to avoid this behavior. One way, when
224debugging, is to set the option <code>debug.undead = true</code>:</p>
225<pre><code>var Seneca = require(&apos;seneca&apos;)
226var seneca = Seneca({debug: {undead: true}})</code></pre><p>Another is to create a new Seneca instance that does not have a fixed
227<code>fatal$ = true</code> argument:</p>
228<pre><code>var fresh_seneca = this.root.delegate()</code></pre><p>This is necessary for plugins that will send messages once Seneca is
229ready, such as the transport plugins.</p>
230<p><a href="#" class="linkable" style="color: rgba(41, 125, 134, 0.20); display:inline-block; float:left; margin: 8px -80px">[&#x21E7;]</a>
231<a name="q-reply"></a></p>
232<h3 id="how-do-i-respond-to-a-message"><a href="#how-do-i-respond-to-a-message" class="linkable" style="margin-left:-2rem; margin-right:1rem; display:inline-block;font-size:1.2rem;color:rgba(41, 125, 134, 0.20);text-decoration:none;vertical-align:middle">&#xA7;</a>How do I respond to a message?</h3>
233<p>When a message pattern is matched, it triggers execution of the
234associated action function that you have defined. Your action function
235is passed three parameters:</p>
236<ul>
237<li><code>msg</code>: the message that triggered this action.</li>
238<li><code>reply</code>: a callback function that you can use to reply to the message.</li>
239<li><code>meta</code>: a meta data object for tracing and debugging (normally ignored).</li>
240</ul>
241<p>Thus a typical action definition looks like so:</p>
242<pre><code>const Seneca = require(&apos;seneca&apos;)
243
244const seneca = Seneca()
245
246seneca
247  .add({a: 1}, function(msg, reply) {
248    reply(null, {x: msg.y})
249  })</code></pre><p>And to use it, you call:</p>
250<pre><code>seneca.act({a: 1, y: 2}, function(err, out) {
251  console.log(err) // prints null, as there was no error
252  console.log(out) // prints {x: 2}, as that was the response given to `reply`
253})</code></pre><p>The <code>reply</code> callback follows the normal signature for callbacks:
254<code>callback(err, result)</code>. But it also provides some convenience
255abbreviations. You can provide a data response using:</p>
256<ul>
257<li><code>reply(null, {z: 3})</code></li>
258<li><code>reply({z: 3})</code></li>
259</ul>
260<p>You can provide an error response using:</p>
261<ul>
262<li><code>reply(new Error(&apos;my error message&apos;)</code></li>
263</ul>
264<p>And you can provide an empty response using:</p>
265<ul>
266<li><code>reply()</code></li>
267</ul>
268<p>Thus, our example above can be more conveniently written as:</p>
269<pre><code>seneca
270  .add({a: 1}, function(msg, reply) {
271    reply({x: msg.y})
272  })</code></pre><p>It is also common practice to pass the <code>reply</code> callback into another
273function expecting a standard signature callback. For example:</p>
274<pre><code>const Fs = require(&apos;fs&apos;)
275
276seneca
277  .add({file: &apos;read&apos;}, function(msg, reply) {
278    Fs.stat(msg.path, reply)
279  })</code></pre>
280        </div>
281      </div>
282
283      <div class="row center-xs">
284        <div class="col-xs-12 col-md-10 col-lg-10">
285          <p class="txt-lead mb mt2x">Issues? From spelling errors to broken tutorials and everything in between, report
286          them <a href="https://github.com/senecajs/senecajs.org/issues">here.</a></p>
287        </div>
288      </div>
289    </div>
290
291    <footer role="contentinfo">
292    
293      <div class="footer-top">
294        <div class="container-fluid">
295          <div class="row center-xs">
296            <div class="col-xs-12">
297              <img src="/images/logo-seneca-inversed.svg" class="logo-seneca-lg" alt="Seneca" />
298            </div>
299    
300            <div class="col-xs-12 col-sm-4 col-md-3">
301              <p class="mt"><a href="https://github.com/senecajs/seneca" class="link-has-icon icon icon-github">Github</a></p>
302            </div>
303    
304            <div class="col-xs-12 col-sm-4 col-md-3">
305              <p class="mt"><a href="/docs/" class="link-has-icon icon icon-docs">Documentation</a></p>
306            </div>
307            <div class="col-xs-12 col-sm-4 col-md-3">
308              <p class="mt"><a href="https://twitter.com/senecajs" class="link-has-icon icon icon-twitter">Twitter</a></p>
309            </div>
310          </div>
311          <!-- row -->
312        </div>
313      </div>
314      <!-- footer top -->
315    
316      <div class="footer-bottom">
317        <div class="container-fluid txt-center">
318          <p class="mb0">© <a href="https://github.com/rjrodger">Richard Rodger</a> and <a href="https://github.com/senecajs/senecajs.org/contributors">other</a> <a href="https://github.com/senecajs/seneca/contributors">contributors</a> 2010 - 2023. Powered by <a href="http://metalsmith.io">MetalSmith</a>, hosted by <a href="http://surge.sh">Surge</a>. A <a href="https://www.voxgig.com">
318Voxgig</a> project.</p>
319        </div>
320      </div>
321      <!-- footer bottom -->
322    </footer>
323    
324    
324<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.0.0/highlight.min.js"></script>
324
325    
325<script>hljs.initHighlightingOnLoad();</script>
325
326    
327    
327<script src="https://cdnjs.cloudflare.com/ajax/libs/zepto/1.2.0/zepto.min.js" integrity="sha256-vrn14y7WH7zgEElyQqm2uCGSQrX/xjYDjniRUQx3NyU=" crossorigin="anonymous"></script>
327
328    
328<script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script>
328
329    
329<script type="text/javascript"> docsearch({
330        apiKey: 'a5afa8843727758cbaa7fbacb932b215',
331        indexName: 'senecajs',
332        inputSelector: '#seneca-search-input'
333    });
334    </script>
334    
334<script>
vendor: 363 bytes, lines 334-340
334
335      (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
336      (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
337      m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
338      })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
339    
340      ga('create', '
340UA-57673-6
vendor: 54 bytes, lines 340-342
340', 'senecajs.org');
341      ga('send', 'pageview');
342    
342</script>
342
343  
343<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"347dc49995754bb7b7965337d6cf85df","r":1,"spa":2}' crossorigin="anonymous"></script>
343
344</body>
345</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.