Problem Writing in file in a Docker Nodejs Image

37 Views Asked by At

I'm doing an activity where I need to write information to a file when an image requires access to this resource, as shown below. This is how my folders are organized. node2 requests access to node1.

enter image description here

The code below is responsible for applying a type of mutual exclusion, preventing simultaneous access to the file. The problem is when access is granted, nothing is being written to the file, despite console.log(logEntry) showing the result that was supposed to be written

const sharedFilePath = path.join(__dirname, 'data', 'shared-file.txt');

let isResourceLocked = false;

app.get('/request-access/:deviceId', (req, res) => {
  const deviceId = req.params.deviceId;
  
  if (!isResourceLocked) {
    isResourceLocked = true;

    // Registrar no arquivo compartilhado
    const timestamp = new Date().toISOString();
    const logEntry = `Device ${deviceId} accessed the resource at ${timestamp}\n`;
    console.log(logEntry)
   
    fs.appendFileSync(sharedFilePath, logEntry, (err) => {
      if (err) return console.log(err);
      console.log('Log entry added to shared file:', logEntry);
    });
    

    // Liberar o recurso após um período simulado (por exemplo, 5 segundos)
    setTimeout(() => {
      isResourceLocked = false;
    }, 5000);

    res.send(`Access granted to Device ${deviceId}`);
  } else {
    res.send(`Resource is currently locked. Device ${deviceId} must wait.`);
  }
});

In this code I require access to write to the file

app.get('/', async (req, res) => {
  const deviceId = 'Node1'; // Identificador único para cada nó
  try {
    const response = await axios.get(`${coordenadorUrl}/request-access/${deviceId}`);
    console.log(coordenadorUrl)
    res.send(response.data);
  } catch (error) {
    res.send('Error requesting access to the resource.');
  }
});

Dockerfile of every node is like this

FROM node:14

WORKDIR /usr/app

COPY package*.json ./

RUN npm install

RUN mkdir -p data

COPY . .

CMD ["npm", "start"]

docker-compose.ymml

version: '3.8'
services:
  app:
    build:
      context: ./node1
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - EXTERNAL_PORT=3000
    volumes:
      - ./node1/data:/usr/src/app/data
    networks:
      - my-network # Adiciona o serviço à rede personalizada

  app2:
    build:
      context: ./node2
      dockerfile: Dockerfile
    ports:
      - "3002:3002"
    environment:
      - EXTERNAL_PORT=3002
    networks:
      - my-network # Adiciona o serviço à rede personalizada

networks:
  my-network: # Defina uma rede personalizada
    driver: bridge
1

There are 1 best solutions below

0
datawookie On BEST ANSWER

You need to share the same volume with both of the containers. Suppose that you have a simple add that logs to a file:

app.js

const fs = require('fs');

const path = '/usr/src/app/data/shared-log.txt';

const id = process.env.ID || 'Default';

const appendContent = () => {
    const now = new Date();
    const timestamp = now.toISOString();
    
    const contentToAdd = `${timestamp}: Data from: ${id}\n`;

    fs.appendFile(path, contentToAdd, err => {
        if (err) {
        console.error('An error occurred:', err);
        return;
        }
        console.log('Line appended successfully');
    });
};

setInterval(appendContent, 5000);

Wrap that up in a Docker image.

Dockerfile

FROM node:14

WORKDIR /usr/app

COPY package*.json ./

RUN npm install

RUN mkdir -p data

COPY . .

CMD ["node", "app.js"]

There's a minimal package.json.

Now a Docker Compose configuration that creates two instances of the container.

docker-compose.yml

version: '3.8'
services:
  first:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      - ID=first
    volumes:
      - .:/usr/src/app/data
      
  second:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      - ID=second
    volumes:
      - .:/usr/src/app/data

Note that both of those have the same location volume mounted and that the script is writing to the mounted location.

When you bring up Docker Compose you'll find that the two containers write to the same log file (which will be located in the current directory on the host).

enter image description here

This does not set up locking to prevent simultaneous writing to the file. However it does demonstrate the general principle of how you can set up two containers to write to the same shared file.