Running scripts in Production
Tags: env, config, script
Published: 2024-01-18 11:47:59

## Introduction
When operating software in production, you need to run some on-off scripts or migrations to consult or perform some manual tasks until they are automated somehow.
To make this possible and safe we made some improvements in our codebase.

## .env.stg

When we need to run a script in staging, we have a special environment variable ENV_FILE, that let us customize what .env file to load:

```jsx
ENV_FILE='.env.stg' yarn w path/to/script.ts
```

`yarn w` is how we run our scripts, it uses webpack to bundle the script and run it using node.

Here is the implementation of ENV_FILE

```jsx
import dotenvSafe from 'dotenv-safe';
import path from 'path';

import pkg from '../package.json';

const cwd = process.cwd();

const root = path.join.bind(cwd);

const getEnvFile = () => {
  if (process.env.ENV_FILE !== undefined) {
    return process.env.ENV_FILE;
  }

  return '.env';
};

const envFile = getEnvFile();

dotenvSafe.config({
  path: root(envFile),
  sample: root('.env.example'),
});

if (process.env.NODE_ENV === 'development') {
  // eslint-disable-next-line
  console.log('.env: ', path.join(cwd, envFile));
}
```

It will also `console.log` what .env file it was loaded

## Script Run Confirmation

Before running the script, we show some environment variables and ask to confirm

```jsx
let rl: Interface | null = null;

export const ask = (question: string): Promise<string> => {
  if (!rl) {
    rl = readline.createInterface({ input, output });
  }

  return new Promise((resolve) => {
    rl.question(question, (answer) => resolve(answer));
  });
};


export const prompt = async () => {
  // eslint-disable-next-line
  console.log({
    MONGO_URI: config.MONGO_URI,
    REDIS_HOST: config.REDIS_HOST,
    APP_ENV: config.APP_ENV,
  });

  if (process.env.CONFIRM_PROMPT !== 'true') {
    return;
  }

  const answer = await ask('Run ? (y/n)');

  if (answer?.toLowerCase() !== 'y') {
    throw new Error('Aborted');
  }
};

``` 

![Confirmation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iflp8ub4gsij3y1twey7.png)

## onlyLocalhost

We also have a function `onlyLocalhost` that we use in some scripts like seed or drop database that should never being run against staging or production environment.

```jsx
export const onlyLocalhost = () => {
  if (
    config.MONGO_URI !== 'mongodb://localhost/woovi' &&
    config.MONGO_URI !==
      'mongodb://mongo1:27017,mongo2:27017/woovi?replicaSet=rs0'
  ) {
    throw new Error(`MONGO_URI is not localhost: ${config.MONGO_URI}`);
  }
}
```

If we try to run a script with `onlyLocalhost()` against staging or production it will break the script from running.

## In Short
Sometimes you can't avoid running a script in production to provide a quick fix for some unexpected behavior.
If you need to make this, try to add this tooling to make it fast, and avoid running `DROP DATABASE` in production.

---
Woovi
[Woovi](https://www.woovi.com) is a Startup that enables shoppers to pay as they like. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.

If you want to work with us, we are [hiring](https://woovi.com/jobs/)!

---
<a href="https://www.freepik.com/free-ai-image/glowing-neon-waves-illuminate-dark-backgrounds-futuristic-designs-generated-by-ai_49573304.htm#query=devops&position=4&from_view=search&track=sph&uuid=3cb20555-29f2-4f1a-abcb-a71bbdab14cf">Image By vecstock</a>