Avoid design time CAP server restarts when maintaining local data files
Starting the CAP server with cds watch
is great for tight development loops at design time, especially with the built-in in-memory SQLite persistence layer, seeded by data in CSV files. When the server notices files have changed, it automatically restarts, which is great.
But sometimes you want to maintain files and not have the server restart, perhaps because you have made modifications or additions to the data set that's being served, and don't want to lose that by such a restart.
Here's a quick hack to achieve that.
Behind the scenes
If you set the DEBUG environment variable appropriately when running cds watch
, like this:
DEBUG=cli cds watch
then you see a little bit more of what's going on behind the scenes:
[cds] - @sap/cds 7.6.3 loaded: /usr/lib/node_modules/@sap/cds-dk/node_modules/@sap/cds
[cds] - Command resolved: /usr/lib/node_modules/@sap/cds-dk/bin/watch.js
[cli] - live reload available at http://127.0.0.1:35729/livereload.js?snipver=1
cds serve all --with-mocks --in-memory?
9734 watching: cds,csn,csv,ts,mjs,cjs,js,json,properties,edmx,xml,env ...
ignoring: (node_modules|_out|@types|@cds-models)\/|app(\/.+)?\/((webapp|dist|target)\/|tsconfig\.json$|.*\.tsbuildinfo$)
live reload enabled for browsers
[cli] - livereload ignored: .vscode
...
[cds] - @sap/cds 7.6.3 loaded: /usr/lib/node_modules/@sap/cds-dk/node_modules/@sap/cds
[cds] - Command resolved: /usr/lib/node_modules/@sap/cds-dk/bin/serve.js
[cds] - loaded model from 2 file(s):
srv/cat-service.cds
db/data-model.cds
[cds] - connect using bindings from: { registry: '~/.cds-services.json' }
[cds] - connect to db > sqlite { database: ':memory:' }
> init from db/data/my.bookshop-Books.csv
/> successfully deployed to in-memory database.
[cds] - using auth strategy {
kind: 'mocked',
impl: '../../usr/lib/node_modules/@sap/cds-dk/node_modules/@sap/cds/lib/auth/basic-auth'
}
[cds] - serving CatalogService { path: '/odata/v4/catalog' }
[cds] - server listening on { url: 'http://localhost:4004' }
[cds] - launched at 4/10/2024, 8:55:34 AM, version: 7.6.3, in: 736.516ms
[cds] - [ terminate with ^C ]
[cli] - live reload for . 0 ws clients
It's the "ignored" lines that we're interested in, rather than any containing "livereload", which is related, but separate.
It's these two log lines that are interesting here:
9734 watching: cds,csn,csv,ts,mjs,cjs,js,json,properties,edmx,xml,env ...
ignoring: (node_modules|_out|@types|@cds-models)\/|app(\/.+)?\/((webapp|dist|target)\/|tsconfig\.json$|.*\.tsbuildinfo$)
The CAP server uses node-watch behind the scenes providing the watch-and-restart mechanism. And it has a default regular expression, which we can see here, to describe file and directory name patterns that this mechanism should ignore.
Normal behaviour
Sometimes when marshalling data for an OData CREATE operation, for example, I'll use a file to store the JSON payload for such an operation. If I were to create or maintain the contents of a file called data.json
in the project root, for example, like this:
touch data.json
then the CAP server would be restarted:
[cli] - Restart { events: [ { type: 'update', name: '/tmp/watchme/data.json' } ] }
[cli] - ⚡️ SIGTERM 15 received by cds serve
[cli] - ⚡️ cds serve - cds.shutdown
[cli] - ⚡️ cds serve - server.close(d)
[cli] - ⚡️ cds serve - process.beforeExit
[cli] - ⚡️ cds serve - process.exit
[cli] - ⚡️ cds watch - child exited 9745
___________________________
[cds] - @sap/cds 7.6.3 loaded: /usr/lib/node_modules/@sap/cds-dk/node_modules/@sap/cds
[cds] - Command resolved: /usr/lib/node_modules/@sap/cds-dk/bin/serve.js
...
[cds] - serving CatalogService { path: '/odata/v4/catalog' }
[cds] - server listening on { url: 'http://localhost:4004' }
[cli] - live reload for /tmp/watchme/data.json. 0 ws clients
[cds] - launched at 4/10/2024, 8:58:31 AM, version: 7.6.3, in: 732.947ms
[cds] - [ terminate with ^C ]
This would mean that the state of the in-memory data set served by my services would be lost and reset to the original CSV data file based state through the normal restart process.
Avoiding normal behaviour
If I wanted to avoid that happening, I could create a directory whose name was matched by the "ignore" regular expression. For example, If I could create a directory called _out/
in the project root:
mkdir _out/
And then any creation or maintenance of files in that directory:
touch _out/data.json
would not result in the server being restarted:
[cli] - ignored: _out
[cli] - livereload ignored: _out
[cli] - ignored: _out
[cli] - ignored: _out/data.json
Good to know!