📜 ⬆️ ⬇️

We write a web service for 1 evening

Prehistory


I recently ordered one thing from England to me in my native St. Petersburg. The package was shipped by EMS. And what was my surprise when I discovered that I could not track the status of the parcel automatically by the track number (departure identifier) ​​issued to me. Possessing a very impatient character, I literally every morning began by checking the status of my package. And he was even more upset when he realized that she was still there, where she was 5 days ago. After some thought, I decided that this was a terrible omission, and decided to rectify the situation on my own.


Build a bike


Yes, dear friend, such services already exist, and probably even work, but it's always so nice to do something with your own hands. Moreover, registration is required on all these services, and nowadays it is an unforgivable pleasure to get one more account on the site, which is needed once a year.

Here are examples of existing services:
gdeposylka.ru - after registration they promise e-mail notifications, for a fee they will even send sms
post-tracker.ru - here, too, promise automatic notifications after registration
')

Let's start


Well, the first thing I did, of course, was choosing a domain name, I needed something so cool, sonorous, I stopped at: trackmypost.ru

In my opinion fully reflects the idea of ​​the project.

Next, it was necessary to find a platform, I needed a normal virtual machine with root access and the ability to gather everything together for myself, and my choice fell on hetzner.de .

The result is a pleasant part of creating a service: I have a cool domain and a “machine”. It remains to write the service itself.
First, let's deploy nginx, php-cli, php-fpm, mysql, ssmtp and postfix. CLI will do the dirtiest work, out of it will work 2 of our "demon". In fact, this is just 2 scripts starting at a crown every minute . The first will actually track mailings, and the second will send mail notifications.

Speaking of architecture, why I divided these 2 scripts: I do not know how many letters will be there in the queue, how postfix will work, etc. Therefore, in order to protect against the hang of the entire service, I divided 2 logical operations: tracking and sending notifications. By the way, with this option it is much more convenient to collect statistics and generally monitor what is happening on the service.

Data


It's time to think about where and how to store data. The simplest storage is mysql. I will not paint all the fields, I’ll just mark the key points, of course, for the task table for tracking (let's call it tasks), we will need the last_state field (the last status of the package) and bounce (the number of unsuccessful attempts to find the track on sites) and bounce_date (the date of the last unsuccessful attempt to find the track).

Tracking


General

The first script, let's call it tracker.php, makes requests to emspost.ru and russianpost.ru servers in order to check the status of the notification.

If the servers are answered, but the track number is not found on them , then increase the bounce field of the current task by 1 and set bounce_date equal to the value of the current date. bounce_date allows you to forget about this task today.
For bounce, I implemented this logic:


If the track is found on one of the sites and the current status! = Last_state send a notification about the status change.

If the new status is “Handing to the addressee”, then we’ve finished tracking the track.

Trekking queue

I needed to implement a simple and uniform queue for tracking, and I did this: each time the script is run, only one track number is selected and processed in tracker.php. After processing, this track is recorded in the file last_track.txt. At the next launch, the script selects id> ID values ​​from last_track.txt. When it comes to the last one starts from the beginning.
In this way:

Mailing


With mail, everything is quite simple. In fact, tracker.php itself does not call the mail () function, it only adds the letter to the mysql mails label. Which is already raking the second script launched according to crown: mailer.php.

For each launch, he simply chooses the next, not sent letter, and tries to send it. If the mail () function returns true, it is marked as sent. If false and postfix broke, then the same email will try to leave again in a minute.

Afterword


I only needed FPM for processing the form of adding a track and issuing statistics.

When writing a class for socket requests, do not forget to set the timeout for reading and writing, in php this is done something like this:

fputs ($ fp, $ data);
$ result = '';
while (! feof ($ fp) && (! $ info ['timed_out'])) {
$ result. = fgets ($ fp, 128);
$ info = stream_get_meta_data ($ fp);
}
fclose ($ fp);

Because, for example, the site of the Russian Post is sinning by not closing the connection even with Connection: close.

As usual, do not forget to disable keep-alive in nginx by setting it to 0 seconds.

You can leave your questions and comments right here, or on the project website: trackmypost.ru =)

Source: https://habr.com/ru/post/130989/


All Articles