This the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Setup

Setup and configuration of client and server

This section will walk you through the many options of how to setup and operate FactCast.

1 - Prerequisites

Postgres

In order to run the FactCast server, you have to provide a Postgres database at least in version 15. The following example shows the configuration with one user.

spring.datasource.username="user" //that user has to be provided
spring.datasource.password="password"

The user has to be a superuser, as he will also install Postgres modules like uuid-ossp.

If you don’t want to provide a superuser

If you don’t want to provide a superuser, you have to consider the following points:

1.) The database user needs at least the permission to query the pg_roles view. According to the documentation it’s publicly accessible, so that shouldn’t be a problem.

2.) The FactCast needs the Postgres module uuid-ossp. You have to install that module manually. The server will recognize the already installed module and it won’t throw an error caused by missing privileges. Login into your Postgres console and execute the following command as superuser:

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

2 - fat-jar

Building

First of all, build factcast completely if not yet done by running

mvn install

In order to run a simple example FactCast server, you could enter the project factcast-examples/factcast-example-server and run

mvn spring-boot:run

or run it in your IDE. Note that it will use TestContainer to start an ephemeral postgres instance for you. That means, you need to have a runnable Docker installed on your machine.

In case you want to use your local Postgres instead, take a look at ExampleServerWithPostgresContainer to find out how what is necessary to use a pgsql. After all, this is just a very simple Spring Boot application using JDBC.

As expected, running

mvn package

will create a standard spring boot fat jar target/factcast.jar that can be run instantly.

Read more on Ports

3 - fat-jar (TLS)

Non-Encrypted

In order to run a simple example FactCast server, you could enter the project factcast-examples/factcast-example-server, see fatjar

TLS Server

There is an extra example project that demonstrates the usage of TLS for your server that can be found factcast-example-tls-server

We tried to stick as close as possible to what we have in factcast-examples/factcast-example-server to demonstrate the necessary changes and nothing more.

Obviously, for running a TLS Server, you need a certificate. We packaged a snakeoil localhost certificate for you to test. This cert can be found in src/etc/certificates/. In order to create your own selfsigned certificate, there is a shell script you can use as a starting point.

obviously, you should use proper trusted certificates when you run FactCast in production - you have been warned

In order to run the TLS Server, go to factcast-examples/factcast-example-tls-server and run

mvn spring-boot:run

Read more on Ports

4 - Ports

Port defaults and how to change them

The default TCP-Port exposed is 9090. As usual, you can set it via environment variables.

Standard ports used:

PortProtocolComponentProperty
9090HTTP2factcast-server-grpcgrpc.server.port (for the bind address: grpc.server.host, defaults to 0.0.0.0)

5 - Security

Authentication & Authorization

In order to control access the FactCast Server supports a very basic way of defining which client is allowed to do what. The security feature is enabled by default, but can be disabled (for integration tests for example) by setting factcast.security.enabled to false.

In order to make use of the security features, a Bean of type FactCastAccessConfig must be defined. This is done either by providing one in your FactCast Server’s context, or by using the dead-simple approach to put a factcast-access.json on the root of your classpath or at /config/ to deserialize it from there.

Example below.

Now, that you’ve defined the access configuration, you also need to define the secrets for each account. Again, you can do that programmatically by providing a FactCastSecretsProperties, or by defining a property for each account like this:

factcast.access.secrets.brain=world
factcast.access.secrets.pinky=narf
factcast.access.secrets.snowball=grim

The catch with this simple approach of course is, that credentials are stored in plaintext in the server’s classpath, but remember it is just a dead-simple approach to get you started. Nobody says, that you cannot provide this information with a layer of your docker container, pull it from the AWS Parameter Store etc…

If FactCast misses a secret for a configured account on startup, it will stop immediately. On the other hand, if there is a secret defined for a non-existing account, this is just logged (WARNING-Level).

The contents of factcast-access.json might look like:

{
	"accounts": [
		{
			"id": "brain",
			"roles": ["anything"]
		},
		{
			"id": "pinky",
			"roles": ["anything", "limited"]
		},
		{
			"id": "snowball",
			"roles": ["readOnlyWithoutAudit"]
		}
	],
	"roles": [
		{
			"id": "anything",
			"read": {
				"include": ["*"]
			},
			"write": {
				"include": ["*"]
			}
		},
		{
			"id": "limited",
			"read": {
				"include": ["*"],
				"exclude": ["secret"]
			},
			"write": {
				"exclude": ["audit*"]
			}
		},
		{
			"id": "readOnlyWithoutAudit",
			"read": {
				"include": ["*"],
				"exclude": ["audit*", "secret"]
			},
			"write": {
				"exclude": ["*"]
			}
		}
	]
}

Where pinky & brain are authorized to use the full FactStore’s functionality (with ‘pinky’ not being able to write to namespaces that start with ‘audit’) whereas snowball can only read everything but ‘audit’-namespaces, but not write anything.

In case of conflicting information:

  • explicit wins over implicit
  • exclude wins over include

Note, there is no fancy wildcard handling other than a trailing ‘*’.

see module examples/factcast-example-server-basicauth for an example

Using BasicAuth from a client

From a client’s perspective, all you need to do is to provide credentials. Once the credentials are configured, they are used on every request in a Basic-Auth fashion (added header to request).

factcast.grpc.client.user and factcast.grpc.client.password are the properties to set.

You can always use environment variables or a -D switch in order to inject the credentials.

see module examples/factcast-example-client-basicauth for an example

Customizing Credential Loading

If you dont want to configure your passwords via properties, you can provide either a custom FactCastSecretProperties bean or an implementation of a UserDetailsService. That’s a simple interface coming from Spring Security which provides a mapping method from username to user. In our case we have to return a FactCastUser.

If you want to externalize secret loading but want to keep the factcast-access.json file for managing authorization an implementation of such a UserDetailsService could look like this:

@Bean
UserDetailsService userDetailsService(FactCastAccessConfiguration cc, PasswordEncoder passwordEncoder) {
    return username -> {
        // fetching account info from fact-access.json
        Optional<FactCastAccount> account = cc.findAccountById(username);

        // your way to fetch the user + password
        User user = loadUserByName(username);

        return account
            .map(acc -> new FactCastUser(acc, passwordEncoder.encode(user.getPassword())))
            .orElseThrow(() -> new UsernameNotFoundException(username));
    };
}

6 - gRPC Client

GRPC Clients

In order to talk to a - not in process - factstore (which is the usual setup for non-test applications), GRPC is the communication protocol used.

Using FactCast client in Spring boot via GRPC

If you use Spring take the easy path in your Spring Boot Application by adding the appropriate dependencies to your application:

   <dependency>
     <groupId>org.factcast</groupId>
     <artifactId>factcast-client-grpc</artifactId>
   </dependency>
   <dependency>
     <groupId>org.factcast</groupId>
     <artifactId>factcast-spring-boot-autoconfigure</artifactId>
   </dependency>

There are example projects: factcast-examples/factcast-example-client-spring-boot2 and factcast-examples/factcast-example-client-spring-boot1 respectively, that you can use as a template.

Note that factcast-client-grpc is built on top of (https://github.com/yidongnan/grpc-spring-boot-starter). If you are looking for the basic configuration properties, that is where you can find the latest version.

At the time of writing, the most relevant are:

NameExample Valuerequired
grpc.client.factstore.addressstatic://localhost:9090yes
grpc.client.factstore.negotiationTypePLAINTEXTno
grpc.client.factstore.enable-keep-alivetrueno

6.1 - gRPC BasicAuth

Using BasicAuth from a client

From a client’s perspective, all you need to do is to provide credentials. Once the credentials are configured, they are used on every request in a Basic-Auth fashion (added header to request).

In order to define credentials, just set the appropriate property to a value of the format ‘username:password’, just as you would type them into your browser when a basic-auth popup appears.

# if this property is set with a value of the format 'username:password', basicauth will be used.
grpc.client.factstore.credentials=myUserName:mySecretPassword

You can always use environment variables or a -D switch in order to inject the credentials.

see module examples/factcast-example-client-basicauth for an example

6.2 - gRPC KeepAlive

keep-alive settings

Here are some good settings for an initial configuration of a SpringBoot FactCast client/server setup in case you ran into gRPC related client server communication troubles.

  • Sending keep-alive HTTP/2 PINGs on the connection is useful in case you are running on infrastructure that doesn’t support configurable idle timeouts, and therefore closes connections.

  • The proposed values are defining a scenario where the client sends keep-alive HTTP/2 PINGs every 300s and the server accepts this behavior without sending GO_AWAY ENHANCE_YOUR_CALM to the client. Please adapt to your specific needs.

Client side

PropertyDescriptionRecommendedDefault
grpc.client.factstore.enable-keep-aliveConfigures whether keepAlive should be enabled.truefalse
grpc.client.factstore.keep-alive-timeThe default delay before sending keepAlives. Please note that shorter intervals increase the network burden for the server.30060
grpc.client.factstore.keep-alive-without-callsConfigures whether keepAlive will be performed when there are no outstanding RPCs on a connection.truefalse

Further details can be found here : net.devh.boot.grpc.client.config.GrpcChannelProperties.

Server side

PropertyDescriptionRecommendedDefault
grpc.server.permit-keep-alive-without-callsConfigures whether clients are allowed to send keep-alive HTTP/2 PINGs even if there are no outstanding RPCs on the connection.truefalse
grpc.server.permit-keep-alive-timeSpecifies the most aggressive keep-alive time in seconds clients are permitted to configure.100300

Further details can be found here : net.devh.boot.grpc.server.config.GrpcServerProperties.

6.3 - gRPC Resilience

Resilience approach

In order to make it easier for clients to deal with errors, we try to mitigate connection or network errors, or RetryableExceptions in general by just retrying. There are two types of gRPC communications within the FactCast gRPC API:

  • synchronous, request / response
  • asynchronous, request / streaming response

While the first can be mitigated easily by retrying the call, things get more complicated in an asynchronous, streaming scenario. Imagine a subscription to particular facts (let’s say 10) from scratch, where after 5 successfully received facts the network connection fails. Now simply retrying would mean to receive those 5 facts again, which is not only wasteful, but also hard to handle, as you’d need to skip those rather than process them a second time. Here the FactCast gRPC client keeps track of the facts successfully processed and resubscribes to the ones missing. In this example, it’ll try to subscribe to the same factstream but starting after the fifth fact.

Resilience is supposed to “just work” and let you deal with just the non-transient errors. This is why it is enabled by default with sane defaults.

If you want to disable it completely for any reason, you always can use

factcast.grpc.client.resilience.enabled=false

See properties for the defaults.

7 - Compression

Selecting a compressor

Why ?

Wherever there is network communication, the question of compression comes up. The FactCast server currently supports three compressors out of the box:

  • LZ4
  • Snappy
  • GZip

Unfortunately, GRPC does not support stream-compression, but only message-compression. This means that the efficiency of the compression is dependent on the message size. We’ll get to that…

Client chooses

In order to agree on which compressor to use, there is an initial handshake when the client connects to the server, in which the available compressors on client and server are compared, and the server selects the one to use.

The server send a list of what he accepts, and the client picks his favorite compressor out of that list in the order shown above (LZ4 first, then snappy, GZip as a fallback).

As the client should be low on dependencies and assumptions, Gzip (as supported by the JDK) is the default compressor every client supports.

In order to prefer snappy or LZ4, you’d need to add one or both of the following dependencies (or later versions) to your client and server. Once they are on the classpath on both sides, the client will pick them up automatically, and the server will prefer them over GZip. It is advised, that you use as many codecs as you possibly want to support in the server, and just the preferred one on the client side.

For obvious reasons, extra dependencies to factcast-grpc-myCompressionAlgorithm may bring new transitive dependencies (like commons-compress or net.jpountz for example). As always: please check for potential conflicts.

Snappy


<dependency>
    <groupId>org.factcast</groupId>
    <artifactId>factcast-grpc-lz4</artifactId>
    <version>${factcast.version}</version>
</dependency>

LZ4


<dependency>
    <groupId>org.factcast</groupId>
    <artifactId>factcast-grpc-snappy</artifactId>
    <version>${factcast.version}</version>
</dependency>

For versions before 0.7.9 the respective dependencies were

Snappy


<dependency>
    <groupId>org.xerial.snappy</groupId>
    <artifactId>snappy-java</artifactId>
    <version>1.1.8.4</version>
</dependency>

LZ4


<dependency>
    <groupId>net.jpountz.lz4</groupId>
    <artifactId>lz4</artifactId>
    <version>1.3.0</version>
</dependency>

org.xerial.snappy and net.jpountz.lz4 are deprecated now and will be removed in 0.8.

Compressor efficiency

As there currently is no stream-compression in GRPC, the server compresses each message transferred to the client separately. The smaller this message is, the less efficient the compression can be. For this reason it is important (during the catchup phase, where you expect a lot of messages) to allow the server to bundle facts into a batch that it will compress and send as one message. The default maximum message size is 3.5MB, but it can be configured up to 32MB.

See factcast.grpc.client.max-inbound-message-size

In the follow phase, this setting is not important, as you don’t want to wait for your batch to fill up before you receive the latest publications from the server. Latency is more important than compression efficiency in that case.

8 - Properties

Properties you can use to configure FactCast

Schemaregistry

PropertyDescriptionDefault
factcast.store.schemaRegistryUrlif a schemaRegistryUrl is defined, FactCast goes into validating mode. The only protocols allowed here are “http”, “https”, “classpath” and “file”. Note that http(s) and file always require two slashes after the colon, e.g. “https://someserver/…” or “file:///root/folder/…”.
factcast.store.validationEnabledCan be used for disabling Fact validation if a schemaRegistryUrl is defined. Useful for mass data ingestion.true
factcast.store.persistentRegistryif fetched Schema and Transformation Documents are persisted into Postgresfalse
factcast.store.allowUnvalidatedPublishIf validation is enabled, this controls if publishing facts, that are not validatable (due to missing meta-data or due to missing schema in the registry) are allowed to be published or should be rejected.false
factcast.store.schemaStoreRefreshCrondefines the cron schedule for refreshing the SchemaRegistry by querying for the latest remote changes*/60 * * * * * (every minute)
factcast.store.allowSchemaReplaceIf a schema can be replaced by an updated version from the registry (not a good idea in production environments)false

Transformation-Registry

PropertyDescriptionDefault
factcast.store.persistentTransformationCacheif Transformed Fact payloads are persistently cached into Postgresfalse
factcast.store.inMemTransformationCacheCapacitywhen using the inmem impl of the transformation cache, this is the max number of entries cached. The minimum value here is 100.100
factcast.store.deleteTransformationsStaleForDayswhen using the persistent impl of the transformation cache, this is the min number of days a transformation result is not read in order to be considered stale. This should free some space in a regular cleanup job. Must be a positive number.14
factcast.store.transformationCacheCompactCrondefines the cron schedule for compacting the transformation result cache0 0 0 * * * (at midnight)

Performance / Reliability

PropertyDescriptionDefault
factcast.store.factNotificationBlockingWaitTimeInMillisControls how long to block waiting for new notifications from the database (Postgres LISTEN/ NOTIFY mechanism). When this time exceeds the notifications is repeated. Minimum value is 5000.15000 (15sec)
factcast.store.factNotificationMaxRoundTripLatencyInMillisWhen FactCast did not receive any notifications after factNotificationBlockingWaitTimeInMillis milliseconds it validates the health of the database connection. For this purpose it sends an internal notification to the database and waits for the given time to receive back an answer. If the time is exceeded the database connection is renewed. Minimum value is 50.200
factcast.store.factNotificationNewConnectionWaitTimeInMillishow much time to wait between invalidating and acquiring a new connection. note: This parameter is only applied in the part of FactCast which deals with receiving and forwarding database notifications. Minimum value is 10.100
factcast.store.page-sizeHow many Facts to fetch from the database in one go. Higher values mean more memory usage. Must be positive.50
factcast.store.indexCheckCronCron expression defining a routine check for index validity0 0 3 * * * (3 am)
factcast.store.tailIndexingEnabledenable/ disable tail indexingfalse
factcast.store.tailManagementCroncron schedule when tail rotation should be carried out0 0 0 * * * (at midnight)
factcast.store.tailGenerationsToKeepthe number of tail indexes to keep. The higher the number, the slower the inserts. Probably 2 or 3 is a good value unless you have a very high tail rebuild frequency and not permanently connected applications (like offline clients for instance). Must be a positive number, maximum is 128.3
factcast.store.minimumTailAgeminimum age of the youngest tail index, before a new one is created7 days
factcast.store.tailCreationTimeoutIndex creation can hang for a long time in case of many open transactions. To avoid this, you can specify a timeout.
We will subtract 5 seconds from the given duration before applying it to setTimeout.
1d
factcast.store.transformationCachePageSizeDefines the max number of Facts being scheduled for transformation in one go. Must be positive and not exceed 32000.100
factcast.store.sizeOfThreadPoolForSubscriptionsThis is the number of threads we create for handling new subscriptions requests. It’s implemented via a fixed thread pool. As soon as the subscription request finishes or enters phase 3 (follow) the thread is freed up again. In earlier versions we used the common FJP which limits the parallelism to the number of cores - 1. If you ever encounter too much database load or too high waiting time for subscriptions this can be an option.100
factcast.store.sizeOfThreadPoolForBufferedTransformationsThis is the number of threads we create for handling buffered transformations. It’s implemented via work stealing thread pool. In early versions we used the common FJP which limits the parallelism to the number of cores - 1.25
factcast.store.readOnlyModeEnabledConfigures FactCast to work in read-only mode. You cannot publish any events in this mode and certain functionality like tail index generation or state token generation is disabled. You can still use a persistent schema store or transformation cache, however they will work in read-only mode. Additionally, liquibase is disabled.false
factcast.store.enumerationDirectModeEnabledDespite of a Schema-Registry being defined or not, if set to true, enumeration of types or namespace will examine the data in the store directly, so that you only see data from already published facts.false

Snapshots

InMem-Snapshots

PropertyDescriptionDefault
factcast.snapshot.local.mem.deleteSnapshotStaleForDaysmin number of days a snapshot is kept even though it is not read anymore. Must be a positive number.90

InMemAndDisk-Snapshots

PropertyDescriptionDefault
factcast.snapshot.local.disk.pathToSnapshotspath to store the snapshots in the file system.java.io.tmpdir
factcast.snapshot.local.disk.maxDiskSpacemax disk space to be used by the SnapshotDiskRepository. The oldest Snapshots will start to be removed after reaching 90% of the allocated space, never reaching 100%. Use 0 for unlimited disk space0

RedisSnapshots

PropertyDescriptionDefault
factcast.snapshot.redis.deleteSnapshotStaleForDaysmin number of days a snapshot is kept even though it is not read anymore. Must be a positive number.90
factcast.snapshot.redis.snapshotCacheRedissonCodecoptional configuration of the codec used for serializing objects from and into the snapshot. When set to RedissonDefault no codec is specified and Redisson will use its current default.MarshallingCodec

JDBC-Snapshots

PropertyDescriptionDefault
factcast.snapshot.jdbc.deleteSnapshotStaleForDaysmin number of days a snapshot is kept even though it is not read anymore. Must be a positive number.90
factcast.snapshot.jdbc.snapshotTableNameoptional name of the table for the snapshots. When not provided the default will be usedfactcast_snapshot

Snapshot Serializers

PropertyDescriptionDefault
factcast.factus.snapshot.compressCompress serialized snapshots before sending them to the snapshot-cachetrue

gRPC

Properties you can use to configure gRPC:

gRPC Client

PropertyDescriptionDefaultExample
grpc.client.factstore.credentialsDeprecated. Please use factcast.grpc.client.user and factcast.grpc.client.password insteadnonemyUserName:mySecretPassword
grpc.client.factstore.addressthe address(es) fo the factcast servernonestatic://localhost:9090
grpc.client.factstore.negotiationTypeUsage of TLS or Plaintext?TLSPLAINTEXT
grpc.client.factstore.enable-keep-aliveConfigures whether keepAlive should be enabled. Recommended for long running (follow) subscriptionsfalsetrue
grpc.client.factstore.keep-alive-timeThe default delay before sending keepAlives. Defaults to 60s. Please note that shorter intervals increase the network burden for the server.300
grpc.client.factstore.keep-alive-without-callsConfigures whether keepAlive will be performed when there are no outstanding RPCs on a connection.falsetrue
grpc.client.factstore.enable-keep-alive=true
grpc.client.factstore.keep-alive-time=300
grpc.client.factstore.keep-alive-without-calls=true

Further details can be found here : net.devh.boot.grpc.client.config.GrpcChannelProperties.

FactCast client specific

PropertyDescriptionDefaultExample
factcast.grpc.client.idServer-side logging mentions this optional id if set in order to help with debugging. If this property is not set, it falls back to the value of spring.application.name${spring.application.name}myClient
factcast.grpc.client.userUser if factcast-security is enabled.myUser
factcast.grpc.client.passwordPassword if factcast-security is enabled.myPassword
factcast.grpc.client.enable-fast-forwardIf the server supports it, enables fast forwarding. This is supposed to speedup frequent queries that cluster around the end of the global Fact-Stream and thus can use dedicated temporary rolling indexes.truefalse
factcast.grpc.client.max-inbound-message-sizeThe GRPC server will chunk messages to not exceed this. Note that one message might contain up to 1000 facts. This value disregards compression. The maximum for this value is 32MB, the minimum is 2 MB. Note that this also limits the maximum transaction bulk size.368230416m
factcast.grpc.client.resilience.enabledEnables resilience mode for subscriptions. If enabled, subscriptions that fail due to networking errors will be transparently resubscribed. (since 0.5.5)truefalse
factcast.grpc.client.resilience.windowDefines the window in which a maximum of retries is defined. (since 0.5.5)PT30S (30 seconds)PT2M (2 Minutes)
factcast.grpc.client.resilience.attemptsDefines the maximum number of attempts that will be done (within a time window defined by resilience.window) before failing and escalating the last exception to the application. (since 0.5.5)1025
factcast.grpc.client.resilience.intervalDefines the wait time between two attempts. (since 0.5.5)PT0.1S (100 millis)PT0.5S
factcast.grpc.client.ignore-duplicate-factsIgnores and skips duplicate exceptions during publishing (does not include conditional publishing when using locks). This might be convenient in cases where you published to a factcast server and get a connection error back (you cannot possibly know if the publish on the server succeeded or not). If you have resilience enabled, the publish would be retried and might (if the first was successful) result in a DuplicateFactException. Setting this to true will make factcast just ignore the exception and go on. There might be a performance problem resulting from this: If you publish a batch of facts and a DuplicateFactException is recieved, factcast will fall back to publishing every single Fact from the batch one-by-one in order to make sure, that after your call, all Facts that are not duplicates will be published.falsetrue

grpc Server

PropertyDescriptionDefaultExample
grpc.server.permit-keep-alive-without-callsConfigures whether clients are allowed to send keep-alive HTTP/2 PINGs even if there are no outstanding RPCs on the connectionfalsetrue
grpc.server.permit-keep-alive-timeSpecifies the most aggressive keep-alive time in seconds clients are permitted to configure. Defaults to 5min.300100
factcast.grpc.bandwith.numberOfFollowRequestsAllowedPerClientPerMinuteafter the given number of follow requests from the same client per minute, subscriptions are rejected with RESOURCE_EXHAUSTED55
factcast.grpc.bandwith.initialNumberOfFollowRequestsAllowedPerClientramp-up to compensate for client startup5050
factcast.grpc.bandwith.numberOfCatchupRequestsAllowedPerClientPerMinuteafter the given number of catchup requests from the same client per minute, subscriptions are rejected with RESOURCE_EXHAUSTED60006000
factcast.grpc.bandwith.initialNumberOfCatchupRequestsAllowedPerClientramp-up to compensate for client startup3600036000
factcast.grpc.bandwith.disabledcompletely disables checking if set to truefalsetrue
grpc.server.permit-keep-alive-without-calls=true
grpc.server.permit-keep-alive-time=100

Blacklist

PropertyDescriptionDefaultExample
factcast.blacklist.typeConfigures where the list of blacklisted facts is retrieved from. One of [POSTGRES, RESOURCE].POSTGRES
factcast.blacklist.locationOnly required if type=RESOURCE. Specifies the URL where the JSON file containing the blacklist is located.classpath:blacklist.jsonfile:/some/path/blocked-facts.json

Testing

PropertyDescriptionDefault
factcast.store.integrationTestModewhen set to true, disables all non-essential memory-internal caches, timing might differ to production of course.false

UI

PropertyDescriptionDefault
vaadin.productionModeShould be set to true, otherwise vaadin tries to generate a dev bundle which is not necessary, and probably will fail.false

Further details can be found here : net.devh.boot.grpc.server.config.GrpcServerProperties.

9 - Docker

Building a FactCast server for integration testing using docker

Building

In order to build a standard docker container from source, enter the project factcast-docker and run

mvn docker:build

This will create a docker container as factcast/factcast and needs nothing more than the database URL to run.

Usage:

The docker container can be started

docker run -e"SPRING_DATASOURCE_URL=jdbc:postgresql://<POSTGRES-SERVER>/<DATABASENAME>?user=<USERNAME>&password=<PASSWORD>" -p 9090:9090 factcast/factcast

Note, that the resulting server is optimized and supposed to be used for integration testing only. Do not use it in production