Horizontal scaling

Introduction

The print has a state containing the job queue and each job's state. To enable horizontal scaling, these states must be persisted.

Solution

MapFish-Print's horizontal scaling solution is based on storing states in a database, for example PostgreSQL. To enable this mode, the file mapfish-spring-application-context-override-db.xml must be copied to mapfish-spring-application-context-override.xml and database connection parameters must be configured (see below).

The database connection must be configured with the following Java system properties:

  • db.host: The database server host name
  • db.port: The database server port (defaults to 5432)
  • db.username: The username to connect to the database
  • db.password: The password to connect to the database
  • db.name: The name of the database
  • db.schema: The schema to use (defaults to public)

The schema must exist, and the necessary tables are created automatically (print_accountings, print_job_results, print_job_statuses)

Database polling can be tuned with these two environment variables:

  • PRINT_CANCEL_OLD_POLL_INTERVAL: How often in seconds the DB is polled for jobs to be canceled (default=60s)
  • PRINT_POLL_INTERVAL: How often in seconds the DB is polled for new jobs (default=0.5s)
Existing MapFish-Print Packages

Existing MapFish-Print distribution packages may already contain functionality to ease the setup of horizontal scaling. For example, if you use the Docker image https://hub.docker.com/r/camptocamp/mapfish_print), you do not need to manually rename the file mentioned above, and a startup script contains functionality to verify database availability before the application server is started.

Docker

In a Docker environment, the system properties should be added in the CATALINA_OPTS environment variable Like that: -D<property name>=<property value>.

Kubernetes

In Kubernetes, you can reuse an environment variable with:

  env:
    - name: PROPERTY_VALUE
      value: test
    - name: CATALINA_OPTS
      value: -D<property name>==$(PROPERTY_VALUE)

The order is important.

Full example where we get the database credentials from a secret:

env:
  - name: PGHOST
    valueFrom:
      secretKeyRef:
        key: hostname
        name: database-credential-secret
  - name: PGPORT
    valueFrom:
      secretKeyRef:
        key: port
        name: database-credential-secret
  - name: PGUSER
    valueFrom:
      secretKeyRef:
        key: username
        name: database-credential-secret
  - name: PGPASSWORD
    valueFrom:
      secretKeyRef:
        key: password
        name: database-credential-secret
  - name: PGDATABASE
    valueFrom:
      secretKeyRef:
        key: database
        name: database-credential-secret
  - name: PGSCHEMA
    value: print
  - name: PGOPTIONS
    value: '-c statement_timeout=30000'
  - name: PRINT_POLL_INTERVAL
    value: '1'
  - name: CATALINA_OPTS
    value: >-
      -Ddb.host=$(PGHOST)
      -Ddb.port=$(PGPORT)
      -Ddb.username=$(PGUSER)
      -Ddb.password=$(PGPASSWORD)
      -Ddb.name=$(PGDATABASE)
      -Ddb.schema=$(PGSCHEMA)