diff --git a/README.md b/README.md index 6129e1a..7a204fa 100644 --- a/README.md +++ b/README.md @@ -19,14 +19,15 @@ fallback user profile discovery. ## Installation -`Dockerfile` and `docker-compose.yml` are provided for easy install +Guppe uses Docker Swarm for easy load balancing Web server replicas ``` git clone https://github.com/wmurphyrd/guppe.git cd guppe cp .env.defaults .env echo DOMAIN=yourdomain.com >> .env -docker-compose up --build -d +docker swarm init --advertise-addr 127.0.0.1 +docker stack deploy --compose-file docker-compose.yml guppe ``` ## Updating @@ -41,7 +42,7 @@ Fetch latest code & restart server: ``` git pull -docker-compose up --build -d +docker stack deploy --compose-file docker-compose.yml guppe ``` ## Optional configuration diff --git a/deliveryWorker.js b/deliveryWorker.js new file mode 100644 index 0000000..d463575 --- /dev/null +++ b/deliveryWorker.js @@ -0,0 +1,52 @@ +require('dotenv').config() +const MongoClient = require('mongodb').MongoClient +const { onShutdown } = require('node-graceful-shutdown') +const ActivitypubExpress = require('activitypub-express') + +const { DOMAIN, DB_URL, DB_NAME } = process.env + +const client = new MongoClient(DB_URL) + +const routes = { + actor: '/u/:actor', + object: '/o/:id', + activity: '/s/:id', + inbox: '/u/:actor/inbox', + outbox: '/u/:actor/outbox', + followers: '/u/:actor/followers', + following: '/u/:actor/following', + liked: '/u/:actor/liked', + collections: '/u/:actor/c/:id', + blocked: '/u/:actor/blocked', + rejections: '/u/:actor/rejections', + rejected: '/u/:actor/rejected', + shares: '/s/:id/shares', + likes: '/s/:id/likes' +} +const apex = ActivitypubExpress({ + domain: DOMAIN, + actorParam: 'actor', + objectParam: 'id', + itemsPerPage: 100, + routes +}) + +client.connect() + .then(async () => { + apex.store.db = client.db(DB_NAME) + let resumeDeliveryTimer + function deliver () { + apex.startDelivery() + // delivery will stop if the queue empties, ensure it keeps running when new work is available + // no effect if called while already running + resumeDeliveryTimer = setTimeout(deliver, 5000) + } + deliver() + onShutdown(async () => { + clearTimeout(resumeDeliveryTimer) + // time for last delivery to finish (need to fix in apex) + await new Promise(resolve => setTimeout(resolve, 3000)) + await client.close() + console.log('Guppe delivery worker closed') + }) + }) diff --git a/docker-compose.yml b/docker-compose.yml index ed89001..905ea2c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,10 @@ version: "3.8" services: guppe: - build: . + image: datatitian/guppe + deploy: + mode: replicated + replicas: 4 restart: always ports: - 443:443 @@ -21,7 +24,24 @@ services: driver: local options: max-size: '10m' - + + worker1: + image: datatitian/guppe + command: [ "node", "deliveryWorker.js" ] + deploy: + mode: replicated + replicas: 8 + restart: always + env_file: '.env' + environment: + DB_URL: 'mongodb://mongodb:27017' + depends_on: + - mongodb + logging: + driver: local + options: + max-size: '10m' + mongodb: image: mongo:4.2 restart: always diff --git a/index.js b/index.js index b8f6f08..e396fda 100644 --- a/index.js +++ b/index.js @@ -49,6 +49,7 @@ const apex = ActivitypubExpress({ actorParam: 'actor', objectParam: 'id', itemsPerPage: 100, + offlineMode: true, // delivery done in workers only routes })