项目作者: RodrigoDeRosa

项目描述 :
Simple package delivery tracking system.
高级语言: Python
项目地址: git://github.com/RodrigoDeRosa/delivery-status.git
创建时间: 2020-01-25T14:44:18Z
项目社区:https://github.com/RodrigoDeRosa/delivery-status

开源协议:

下载


Package Status Control

Server documentation

The server has two main endpoints: one for package status control and one for statistics.

Status control

The server allows package addition with it’s associated status, check a package’s last status and update said status.

Package addition

Packages can be added by sending an HTTP as follows:

```http request
POST /packages
{
“id”: “package_id”,
“inputs”: [
{
“status”: “string”,
“substatus”: “nullable string”
}
]
}

  1. The server's response for said request will be as follows:
  2. ```http request
  3. {"pacakge": "status message"}

Where package will be the message associated to the package’s last known status.

Last known status

It is possible to get a package’s last known status by doing the following HTTP request:

```http request
GET /packages/

  1. In this case, the server's answer will be the same as before.
  2. #### Package status update
  3. It is possible to update a package's status (always going forward in the path to delivery) by doing an HTTP request
  4. with the following characteristics:
  5. ```http request
  6. PATCH /packages
  7. {
  8. "id": "package_id",
  9. "inputs": [
  10. {
  11. "status": "string",
  12. "substatus": "nullable string"
  13. }
  14. ]
  15. }

The answer, again, will be as in the first scenario.

Note: Probably, the most logical solution here would be to send the package ID as a path parameter, leaving the
body just for the input list. Anyway, to avoid two different mappings in this simple solution, the request schema
is the same as in the POST request.

Delivery tracking: This endpoint allows to update a package’s status as it progresses in it’s way to be delivered.

Statistics

It’s possible to query some general information about the registered information in the server by doing the following
HTTP request:

```http request
GET /packages/statistics

  1. In this case, the answer will be as follows:

{
“packages_count”: 1,
“count_by_category”: {
“Delivered”: 1,
“Handling”: 0,
“Lost”: 0,
“Manufacturing”: 0,
“Printed”: 0,
“ReadyToPrint”: 0,
“Shipped”: 0,
“SoonDeliver”: 0,
“Stolen”: 0,
“WaitingForWithdrawal”: 0
}
}

  1. Where `packages_count` indicates the number of packages currently stored in the database and the rest of the fields in
  2. the response refer to each category.
  3. **Note:** In this implementation, the server queries the database every time a request is received in this endpoint. A
  4. way to ease the burden on the connection between the server and the database would be to calculate these statistics
  5. periodically, with a relatively small period, and return directly a value stored in memory. Although there would be
  6. eventual inconsistencies, in those cases where the amount of data in the database is larger, a lot of time would be
  7. saved on each request and a heavy load on the link between server and database would be avoided.
  8. **Note 2:** Even though the server stores only the last known status of each package, it would be an option to store
  9. every known status, in the order they were received, to have also statistics of events lost in the way of the delivery
  10. process. Moreover, these stored object could have timestamps which could be used to calculate some statistics about
  11. time taken between status changes.
  12. ### Health Check
  13. The server has exposed the endpoint `/health/health-check`, created with the sole purpose of health control. The
  14. response is always an HTTP status OK (200).
  15. ## Local Execution
  16. ### Docker
  17. To start the server locally with `Docker` and `docker-compose`, it's necessary to have both of these things installed.
  18. You can get them from:
  19. * [Docker - Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu/)
  20. * [Docker - Mac](https://docs.docker.com/docker-for-mac/install/)
  21. * [docker-compose](https://docs.docker.com/compose/install/)
  22. Once all this is installed, it's simply needed to execute `docker-compose up --build` in the project's root folder.
  23. Background execution needs the addition of one docker parameter, resulting in `docker-compose up --build -d`. In this
  24. second scenario, run `docker-compose down` to stop it.
  25. When running the server with Docker, the container will create a volume where it will host the MongoDB server and will
  26. start the server in question as a Docker service.
  27. ### Makefile
  28. It's also possible to start the server by executing:
  29. * `make prepare`
  30. * `make run`
  31. To do this, it's necessary to:
  32. * Have `python 3.8` installed in your system.
  33. * Have `mongo` installed in your system, running on port 27017.
  34. ### Testing
  35. #### Test Execution
  36. To execute the tests, run the following commands:
  37. * `make prepare`
  38. * `make test`
  39. To do this, it's neecessary to:
  40. Se debe tener en cuenta que es necesario:
  41. * Have `python 3.8` installed in your system.
  42. * Have `mongo` installed in your system, running on port 27017. This is necessary for integration tests due to the lack
  43. of an `::inmemory` option for MongoDB in Python.
  44. #### Coverage
  45. Similar to the previous case, once prepared the environment, execute command `make coverage`
  46. ## Online Server
  47. The server is running on a [Heroku](https://www.heroku.com/) instance. The base URL for it is
  48. `https://package-status.herokuapp.com`. Being it hosted with a free tier account, it's possible for the first request
  49. to take some time as it "awakes" the instance; after this, the response speed goes back to normal. I believe the
  50. inactivity time to sleep for a Heroku instance is about 30 minutes.
  51. ## Geolocation
  52. A possible way of implementing geolocation for a package would be to add the endpoint `/packages/<package_id>/location`,
  53. which would receive a body as follows:

{
“lat”: -34.547244,
“lon”: -58.489286
}
```

Requests could be made periodically to this endpoint in order to register the movement of a package and store either:

  • It’s last position, to save storage space.
  • All registered positions, to be able to create a path if it was necessary and to be able to analyze all possible
    lost or disordered requests.

Server scalability

One of the parameters the server can receive is --proc; this parameter lets the user indicate how many processes will
the server have, being 0 equal to as many processes as cores the machine processor has. This, in addition to
Tornado‘s usage of Python’s coroutines to handle as many simultaneous requests, allows the server to easily answer a
great number of requests.

Because of the problem’s characteristics, it’s possible to add multiple independent instances connected to the same
database to increase the availability of the service. This would be easy as the database connection parameters are
loaded when the server starts.

Regarding the request concurrence, this solution didn’t take into account the case where more than one update request
for the same package is received. In this case, a race condition could take place where the database ends up with an
invalid status for a package (only the last received request will have stored it’s update). To avoid this (and make
the server scalable), a distributed lock server could be set up to avoid clashes between requests that try to update
the same package. One example of such server is etcd.