This repository contains sources of server part of Wroclive iOS app.
(Psst… the app itself is also open-sourced!)
We use Google Cloud for hosting.
We extensively use their free tier, to keep our hosting costs low. The only thing that we actually pay for is storage for App Engine instances, but this is about 0.20 zł (~$0.05) per month (only the instances in US are free and we chose Frankfurt because of GDPR and latency).
Anyway, this is how it works:
And this is the push notification pipeline:
- Handles all traffic to wroclive.app and wroclive.app/api
- Runs code from AppEngine directory
- Every 1h it fetches MPK data (for example available lines and stop locations) from
Firestore
- Every 5 seconds it fetches new vehicle locations from wroclaw.pl/open-data
- If you want to deploy it yourself (
make deploy
), then remember to putGCP-Credentials.json
forapp-engine-firestore
service account in AppEngine directory - Since AppEngine instances should not have state (they may be restarted by Google at whim) every 30s we store last heading/angle update location for every vehicle in the database. If something goes wrong we will use those locations to calculate new headings. This is also nice because now we can update the app without worrying about losing the state.
- Stores persistent data:
- lines - filled by
ComputeEngine-Updater
- stops - filled by
ComputeEngine-Updater
- notifications - filled by
ComputeEngine-Notifications
- push notification tokens - filled by
AppEngine
- send push notifications - filled by
ComputeEngine-Notifications
- lines - filled by
- Single instance named
backend
- Startup script:
/home/USERNAME/on-vm-startup.sh
- Runs code from following directories:
- ComputeEngine
- Manage
ComputeEngine
instance (installations, updates etc.) - Update flow:
make package
to create.zip
package with all of theComputeEngine
modulesmake upload
to send package toGCP
make connect
to log intoGCP
- (on VM)
./install-package.sh
exit
make restart
to restart VM (if needed)
- Manage
- ComputeEngine-Updater
- Simple app that downloads GTFS file from wroclaw.pl/open-data and upload it to
Firestore
- Uses sqlite.org for intermediate processing
- Before installing remember to put
GCP-Credentials.json
forcompute-engine-firestore
service account in ComputeEngine-Updater directory
- Simple app that downloads GTFS file from wroclaw.pl/open-data and upload it to
- ComputeEngine-PubSub
Pub/Sub
subscriber- After receiving
backend-update-gtfs-data
message runsComputeEngine-Updater
- Starts when the
Compute Engine
instance starts - Before installing remember to put
GCP-Credentials.json
forpubsub
service account in ComputeEngine-PubSub directory
- ComputeEngine-Notifications
- Gets latest tweets from @AlertMPK and sends them as push notifications
- Stores notifications in
Firestore
- Starts when the
Compute Engine
instance starts - Before installing remember to put following in ComputeEngine-Notifications directory:
GCP-Credentials.json
forcompute-engine-firestore
service accountTwitter-Credentials.json
- seeTwitter-Credentials-example.json
for detailsAPN-Key.p8
- key for Apple Push Notification serviceAPN-Credentials.json
- seeAPN-Credentials-example.json
for details
- ComputeEngine
- Runs code from CloudFunctions directory
backendStart
function- Looks for
backend
instance onCompute Engine
and starts it - Scheduled by
Cloud Scheduler
- Looks for
backendStop
function- Looks for
backend
instance onCompute Engine
and stops it - scheduled by
Cloud Scheduler
- Looks for
Pub/Sub - following topics need to be created:
backend-stop
backend-start
backend-update-gtfs-data
- Every day at 1am (
0 3 * * *
): publishbackend-stop
message onPub/Sub
- Every day at 5am (
15 3 * * *
): publishbackend-start
message onPub/Sub
- Every day at 3am (
30 3 * * *
): publishbackend-update-gtfs-data
message onPub/Sub
IAM & Admin - following service accounts are used:
-
App Engine default service account
- automatically created by
App Engine
- no configuration needed
- automatically created by
-
app-engine-firestore
- account used byApp Engine
to read/write data inFirestore
- Role: Viewer, Editor
- Key should be exported and placed in AppEngine
-
compute-engine-firestore
- account used inComputeEngine-Updater
andComputeEngine-Notifications
to read/write data inFirestore
- Role: Owner
- Key should be exported and placed in ComputeEngine-Updater and ComputeEngine-Notifications
-
pubsub
- account used for creating subscriptions inComputeEngine-PubSub
- Roles: Editor, Pub/Sub Publisher, Pub/Sub Subscriber
- Key should be exported and placed in ComputeEngine-PubSub
- SSL certificate expiring soon
- Alert: 7 days prior
- Uptime check on
wroclive.app/api
(this will also keep ourApp Engine
instance alive)- Protocol: HTTPS
- Hostname: wroclive.app
- Path: api
- Check frequency: 10 minutes
- Regions: Europe
-
We use winstonjs/winston with
@google-cloud/logging-winston
backend -
Add following filers:
- App Engine life cycle
- Query:
resource.type="gae_app" AND (textPayload=~"(Starting app|Quitting on terminated signal)$" OR protoPayload.methodName="google.appengine.v1.Versions.CreateVersion")
- Query:
- Api by user agent
- Query:
protoPayload.userAgent =~ "Wroclive.*"
- Query:
- App Engine life cycle
-
- Parse logs from Cloud Logging and output them in human-readable form
Error reporting - standard reporting by mail
-
- preset to
Unix siege
tool + baseline - used to check burst performance - tiny module written in Python to check sustained performance
- preset to
-
postman.json - configuration file to import into postman app (it contains our endpoints + some basic tests)
Wroclive is licensed under the Mozilla Public License 2.0 license. See LICENSE for more information.