Many months ago I wrote a quick post on OpenWhisk, serverless, and persistence (Serverless and Persistence). In that article I mentioned that while your serverless actions are stateless and you should not rely on the file system, you do have access to it and can make use of it. It isn't something I'd recommend normally and it should be considered a - if not red flag - at least yellow for "are you sure" before deploying, but there are cases where it might make sense.

This weekend I worked on an action that needed to use a four thousand line text file as a data source. I could have fired up a database or Reddis instance, but that seemed like overkill. I knew that I could easily write code to read the file and then store it in the action's variables scope. That way if the action was run while OpenWhisk had it warm, it wouldn't need to hit the file system again.

I ran into some issues though and thankfully (once again), Rodric Rabbah at IBM helped me out. Let's look at a quick example and I'll describe what's necessary to make it work.

First, the action:

const fs = require('fs');

let contents;

function main(args) {

	if(!contents) {
		console.log('Read from the file system');
		contents = fs.readFileSync(__dirname + '/test.txt','UTF-8');
	}

	return { contents:contents };

}

exports.main = main;

This is incredibly simple, but the two parts to make note of are:

  • In order to read a file in the same directory as the action, you can not just use ./file but must use __dirname. This is what Rodric helped me out with.
  • Secondly - you definitely want to cache to read as I'm doing here. I added a console message just to make sure it worked correctly.

Ok, so that's the code, but you have to do a bit more. In order to ship 2+ files with your action, you have to use a zipped action. That makes you also have to make a package.json. I made a quick one with npm init, just be sure it picks up your entry point matching your file name. In my case it was testtext.js and this is what the package.json looked like:

{
  "name": "texttest",
  "version": "1.0.0",
  "description": "",
  "main": "texttest.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Raymond Camden <raymondcamden@gmail.com> (https://www.raymondcamden.com)",
  "license": "ISC"
}

You then zip up the JavaScript file, the text file, and the package.json and deploy that. I use a script to make it easier:

#!/bin/bash
zip -rq temp.zip texttest.js test.txt package.json
wsk action update safeToDelete/texttest --kind nodejs:6 temp.zip
rm temp.zip

And that's pretty much it. When I couldn't figure this out over the weekend, I went into Chrome DevTools, pasted the entire 4k line file into it, and converted it into a JSON file I could require() in instead.

Anyway - just to complete the post, here is a screen shot of it working and a very important, very wise quote:

Yoda