npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

resplit

v0.1.6

Published

Containerizable utility to read lines of text from input and push into a Redis list.

Downloads

2

Readme

resplit

Containerizable utility to read lines of text from input and push into a Redis list.

Use case

Say we need to import a text file, or lines of output from some process, for further processing.

If we wish to write simple Redis-driven microservices, then the first step is to stream those lines of text into Redis.

This utility can perform that first step. It can be built and run as a Docker container for convenience.

Test run

See development/run.sh https://github.com/evanx/resplit/blob/master/development/run.sh

We will use the utility to lpush lines into the Redis key test:resplit

redisKey='test:resplit'

Let's delete the key for starters.

redis-cli del $redisKey

Now we npm start our test run:

(
echo 'line 1'
echo 'line 2'
echo 'line 3'
) | redisKey=$redisKey npm start

We inspect the list:

$ redis-cli lrange $redisKey 0 5
1) "line 3"
2) "line 2"
3) "line 1"

where we notice that the lines are in reverse order. This is because the utility performs an lpush (left push) operation, and so the last line is at the head (left side) of the list.

See https://redis.io/commands/lpush

Therefore for further processing of the imported lines in order, we would use RPOP to pop lines from right side (tail) of the list:

$ redis-cli rpop $redisKey
"line 1"

Config spec

See lib/spec.js https://github.com/evanx/resplit/blob/master/lib/spec.js

module.exports = {
    description: 'Containerizable utility to read lines of text from input and push into a Redis list.',
    required: {
        redisHost: {
            description: 'the Redis host',
            default: 'localhost'
        },
        redisPort: {
            description: 'the Redis port',
            default: 6379
        },
        redisPassword: {
            description: 'the Redis password',
            required: false
        },
        redisKey: {
            description: 'the Redis list key'
        },
        highLength: {
            description: 'the length of the list for back-pressure',
            default: 500
        },
        delayMillis: {
            description: 'the delay duration in milliseconds when back-pressure',
            unit: 'ms',
            default: 5000
        },
        loggerLevel: {
            description: 'the logging level',
            default: 'info',
            example: 'debug'
        }
    }
};

where redisKey is the list to which the utility will lpush the lines from standard input.

Implementation

See lib/main.js https://github.com/evanx/resplit/blob/master/lib/main.js

inputStream.pipe(split())
.on('error', err => reject(err))
.on('data', line => client.lpushAsync(config.redisKey, line)
.catch(err => reject(err)))
.on('end', () => resolve());

Incidently we delay the input stream using the length of the Redis list for back-pressure:

const inputStreamTransform = function(buf, enc, next) {
    this.push(buf);
    client.llen(config.redisKey, (err, llen) => {
        if (err) {
            this.emit('error', err);
        } else if (llen > config.highLength) {
            logger.warn({llen}, config.delayMillis);
            promiseDelay(config.delayMillis).then(next);
        } else {
            next();
        }
    })
};

where we delay calling next() via promiseDelay when the length of the Redis list is somewhat high.

Appication archetype

Incidently lib/index.js uses the redis-util-app-rpf application archetype.

require('./redis-util-app-rpf')(require('./spec'), require('./main'));

where we extract the config from process.env according to the spec and invoke our main function.

That archetype is embedded in the project, as it is still evolving. Also, you can find it at https://github.com/evanx/redis-util-app-rpf.

This provides lifecycle boilerplate to reuse across similar applications.

Docker

You can build as follows:

docker build -t resplit https://github.com/evanx/resplit.git

from https://github.com/evanx/resplit/blob/master/Dockerfile

See test/demo.sh https://github.com/evanx/resplit/blob/master/test/demo.sh

cat test/lines.txt |
  docker run \
  --network=resplit-network \
  --name resplit-app \
  -e NODE_ENV=production \
  -e redisHost=$encipherHost \
  -e redisPort=$encipherPort \
  -e redisPassword=$redisPassword \
  -e redisKey=$redisKey \
  -i evanxsummers/resplit

having:

  • isolated network resplit-network
  • isolated Redis instance named resplit-redis using image tutum/redis
  • a pair of spiped containers for encrypt/decrypt tunnelling
  • the prebuilt image evanxsummers/resplit used in interactive mode via -i

Redis container

The demo uses tutum/redis where we use docker logs to get the password:

docker logs $redisContainer | grep '^\s*redis-cli -a'

spiped

See https://github.com/Tarsnap/spiped

We generate a keyfile as follows

dd if=/dev/urandom bs=32 count=1 > $HOME/tmp/test-spiped-keyfile

We then create the two ends of the tunnel using the keyfile:

decipherContainer=`docker run --network=resplit-network \
  --name resplit-decipher -v $HOME/tmp/test-spiped-keyfile:/spiped/key:ro \
  -p 6444:6444 -d spiped \
  -d -s "[0.0.0.0]:6444" -t "[$redisHost]:6379"`
encipherContainer=`docker run --network=resplit-network \
  --name resplit-encipher -v $HOME/tmp/test-spiped-keyfile:/spiped/key:ro \
  -p $encipherPort:$encipherPort -d spiped \
  -e -s "[0.0.0.0]:$encipherPort" -t "[$decipherHost]:6444"`

Tear down

We remove the test images:

docker rm -f resplit-redis resplit-app resplit-decipher resplit-encipher

Finally we remove the test network:

docker network rm resplit-network