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.
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
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).
🚨 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.