The Scenary
I have a Ubuntu 18.04 server in DigitalOcean with the following specs: 1 vCPUs, 1GB and 25GB Disk.
In this server (let's call API SERVER) I'm using PHP with NodeJS (running in a Proxy managed by apache).
I set up my virtual host with the following specifications (000-default.conf, I'm not using a domain):
DocumentRoot /var/www/html/api
#Allow Htacess Files
<Directory "/var/www/html">
AllowOverride All
</Directory>
#Nodejs (API) Directory Redirection
ProxyRequests Off
ProxyPreserveHost On
ProxyVia Full
KeepAlive On
<Proxy *>
Require all granted
</Proxy>
<Location /node_api>
ProxyPass http://127.0.0.1:3569 retry=0
ProxyPassReverse http://127.0.0.1:3569
</Location>
In /var/www/html
I have two folders:
-
api
folder that contains the api made in php (to be accessed simply enter the server ip); -
node_api
folder that contains the api made in node (to be accessed you need to enter server ip and add/node_api
in URL);
I use PM2 to manage my node server (server.js).
What my API does
Another server makes a request for this server (which is actually an API) more specifically for a file made in PHP.
The PHP file performs some internal analysis, and finally it sends some requests to the api made with node, wait for a response and save in a local file (These requests are sent via CURL
).
$chNodePrintDesktop = curl_init('http://MY_PUBLIC_IP_SERVER/node_api/requestScreenShootForDesktop/');
curl_setopt($chNodePrintDesktop, CURLOPT_HEADER, 0);
curl_setopt($chNodePrintDesktop, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($chNodePrintDesktop, CURLOPT_CONNECTTIMEOUT, 0);
curl_setopt($chNodePrintDesktop, CURLOPT_TIMEOUT, 0);
curl_setopt($chNodePrintDesktop, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
curl_setopt($chNodePrintDesktop, CURLOPT_POSTFIELDS, "urlsite=http://".$argv[2]);
$dataNodePrintDesktop = curl_exec($chNodePrintDesktop);
curl_close($chNodePrintDesktop);
In my case I am sending 5 requests to the node api, each of these requests calls a different route (as we can see in the code above I am calling the route 'requestScreenShootForDesktop'
).
All my 5 routes existing inside my node api, make use of the library called 'puppeteer
'. In this case when I call one of my routes, the node takes the url sent by CURL and returns the data, example from the route /requestScreenShootForMobile/
:
app.post('/requestScreenShootForMobile/', async function(req, res){
const pathUpload = '/var/www/html/node_api/uploads/' + Math.floor(Date.now() / 1000) + '.png';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(req.body.urlsite);
await await page.emulate(devices['iPhone 6']);
await page.screenshot({path: pathUpload});
await browser.close();
var img = await fs.readFileSync(pathUpload);
await res.writeHead(200, {'Content-Type': 'image/png' });
await res.end(img, 'binary');
await fs.unlinkSync(pathUpload);
});
As you can see above, I open and close chrome every time the route is called.
The Problem
In a single request made to the server, php performs the following procedure:
- Performs some internal analyzes.
- Performs 5 CURL'S for different routes to the NODE api (Request a screenshoot for desktop, another for mobile, scrapper all links and so on... all using puppeteer, open and close chrome every time the route is called).
- Save all the data in a .txt file.
During some analysis I noticed that some results made by Node ended up returning error 503 service unavailable
:
The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later Apache/2.4.29 (Ubuntu) Server at MY_PUBLIC_IP_SERVER Port 80
At the first analysis the results usually come out correctly, but as several analyzes are performed (often simultaneously) CURL usually returns error 503 more often.
I try to upgrade the specs of my server (2 Dedicated vCPUs, 4GB and 25GB Disk), use retry=0
in ProxyPass
, but none of that worked.
An interesting point is that although node returns error 503, php always generates the .txt file.
What may be happening and how to solve this problem?