Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

In the table below you can see the pros and cons:

Implementation

Pros

Cons

Main purpose

App & Low Code, Pipelines

Easy to learn. No deep developer skills required. Very fast results possible. No compilation and build steps required. Huge set of out-of-the-box toolings like forms, lists, reports and utils available. Based on many pre-defined standards which can simplify maintenance and upgrading.

Limited to its main purposes. Requires a deployment process.

For data mappings and transformations, workflows and system integrations. Building frontend apps with forms, listings and basic reports.

Microservice

Very flexible: You can use any programming language and libraries of your choice and you can develop any business complexity you like.

Requires developer skills and somebody who reviews and manages the architecture of the microservice. Requires a build and deployment process.

For complex business logics, running mainly as background services.

It's also possible to combine apps and microservices in order to implement a single business solution:

...

  • Sync communication - Typically used with RESTful services inside PIPEFORCE.

  • Async communication - Typically used with RabbitMQ and messaging inside PIPEFORCE (preferred way).

Deploy / Start a Microservice

Once a microservice has been developed, it must be wrapped inside a (Docker) image in order to be able to deploy it into PIPEFORCE. The deployment cycle of a microservice in PIPEFORCE is always an 4-step task:

  1. Build a (Docker) container image from the sources of your microservice.

  2. Upload the container image to a container registry which is supported by PIPEFORCE (for example Docker Hub or the PIPEFORCE Container Registry).

  3. Deploy the image from this registry into your PIPEFORCE namespace by using the command service.start.

Step 2-4 These steps are typically automated by using a CI/CD tool like Jenkins, CircleCI, Travis or similar.

...

...

Default ENV variables

Every time a service is started using the service.start command, also some implicit default variables will be automatically passed to this container and can be accessed via the environment variables inside the container. These implicit variables are:

ENV

Description

PIPEFORCE_DOMAIN

...

The domain name used for the PIPEFORCE instance. For example customer.pipeforce.net.

PIPEFORCE_HUB_

...

HOST

The cluster internal

...

host name of the hub service in order to connect to.

PIPEFORCE

...

PIPEFORCE_SERVICE = The name of this custom service inside PIPEFORCE.

...

_HUB_PORT

The cluster internal host port in order to connect to.

PIPEFORCE_

...

HUB_

...

URL

The cluster internal url of the hub service in order to connect via REST for example.

PIPEFORCE_MESSAGING_DEFAULT_DLQ

...

The default dead letter queue used for RabbitMQ messaging.

...

It is usually pipeforce_default_dlq, but this can change so do not persist this value.

PIPEFORCE_MESSAGING_DEFAULT_

...

EXCHANGE

The default messaging

...

exchange used for RabbitMQ messaging

...

Additionally to these default environment variables, you can also set your custom ones by using the parameter env on the command service.start:

Code Block
languageyaml
pipeline:
  - service.start:
      name: myservice
      image: myimage
      env:
        MY_ENV: "myCustomValue"

Passing secrets as ENV

...

. It is usually pipeforce.default.topic, but this can change so do not persist this value.

PIPEFORCE_MESSAGING_DEFAULT_TOPIC

The default messaging topic used for RabbitMQ messaging. It is usually the same as the default exchange.

PIPEFORCE_MESSAGING_HOST

The messaging host to connect to in order to register a RabbitMQ listener. See below in documentation how to optionally pass messaging username and password as a secret if required. They aren’t provided by default.

PIPEFORCE_MESSAGING_PORT

The messaging host to connect to in order to register a RabbitMQ listener.

PIPEFORCE_NAMESPACE

The namespace of the instance this services runs inside.

PIPEFORCE_PORTAL_URL

The external url to the PIPEFORCE webui portal in order to refer to from inside a microservice.

PIPEFORCE_SERVICE

The name of this custom service inside PIPEFORCE.

PIPEFORCE_STAGE

The staging mode, this namespace is running in. Usually one of DEV, QA or PROD.

Note: Since any value of these ENV variables could change over time, you should never persist them in your microservice!

Custom ENV variables

Additionally to these default environment variables, you can also add your custom ones by using the parameter env on the command service.start:

Code Block
languageyaml
pipeline:
  - service.start:
      name: myservice
      image: myimage
      env:
        MY_ENV: "myCustomValue"

Secret ENV variables

In case you would like to pass secret values to your service ENV variables, you have to do these steps:

  1. Create a secret of type secret-text and with the service name as prefix in the secret store, like this: <yourservice>_<YOUR_SECRET_NAME>.

  2. Use the custom uri $uri:secret:<yourservice>_<YOUR_SECRET_NAME> in the env parameter.

For example, lets assume you would like to start a service myservice and pass a secret with custom name MY_SERVICE to it. For this you have to create a secret with name myservice_MY_SECRET in the secret store and then refer to it like this:

Code Block
languageyaml
pipeline:
  - service.start:
      name: myservice
      image: myimage
      env:
        MY_SECRET_ENV: $uri:secret:myservice_MY_SECRET

On startup of the service, the secret with name myservice_MY_SECRET will be read from the secret store and passed to the container as environment variable MY_SECRET_ENV. This way it is not required to store the secret in code.

Note: Only secrets having the same service name as prefix are allowed to be passed to this service. Any other secret cannot be passed to a service. This is for security reasons.

Info

Since the secret is stored in the environment variable in plain text, make sure to pass secrets only along to trustworthy microservices which belong to your stack!

You can also define a default value for a secret. In case the secret could not be found in the secret store, the given default value will be used and passed as ENV variable value instead:

Code Block
$uri:secret:myservice_MY_SECRET:someDefaultValue

Note: Since this default value is part of your source code, it should only be used in case it is not used in production. For example for demo logins or similar.

Shared secret ENV variables

In case you would like to share a single secret across multiple services, you must prefix it with SHARED_ instead. Secrets prefixed with SHARED_ can be passed to any microservice without security check.

Lets assume you have created a secret with name SHARED_MY_SECRET, then you can pass it to any service like this example shows:

Code Block
languageyaml
pipeline:
  - service.start:
      name: myservice
      image: myimage
      env:
        MY_SECRET_ENV: "$uri:secret:MY_SECRET"

On startup of the service, the secret with name MY_SECRET will be read from the secret store and passed to the container as environment variable MY_SECRET_ENV. This way it is not required to store the secret in code.

Info

Since the secret is stored in the environment variable in plain text, make sure to pass secrets only along to trustworthy microservices which belong to your stack!

You can also define a default value for a secret. In case the secret could not be found in the secret store, the given default value will be used and passed as ENV variable value instead:

Code Block
$uri:secret:MY_SECRET:someDefaultValue:SHARED_MY_SECRET
Note

Important
A secret prefixed with SHARED_ can be passed to ANY service and therefore can also be potentially read by foreign services. This is significantly less secure than prefixing a secret with the specific microservice name. So whenever possible, you should prefer service-name-prefixed secrets over shared secrets in order to increase security.

Monitoring a microservice

...

If you're interested in how to send and receive messages using pipelines, see Messaging and Events Framework.

How to connect a Microservice with the message broker?

...

  • PIPEFORCE_MESSAGING_HOST = The cluster-internal hostname of the messaging service.

  • PIPEFORCE_MESSAGING_PORT = The cluster-internal port of the messaging service.

Info

Note: This The values of these values ENVs can change at any time, so do not use store them as fixed value.

Additionally to these variables, you need to set the PIPEFORCE_MESSAGING_USERNAME and PIPEFORCE_MESSAGING_PASSWORD along with your service.start command using the custom uri prefix $uri:secret. Here is how to do it:

  1. Create a new secret in your secret store with name pipeforce-<yourservice>_messaging-_username and type secret-text and set the RabbitMQ username you would like to use to connect.

  2. Create a new secret in your secret store with name pipeforce-<yourservice>_messaging-_password and type secret-text and set the RabbitMQ password you would like to use to connect.

...

Code Block
pipeline:
    - service.start:
        name: "myservice"
        image: "some/image"
        env:
            PIPEFORCE_MESSAGING_USERNAME: "$uri:secret:pipeforce-myservice_messaging-username"
            PIPEFORCE_MESSAGING_PASSWORD: "$uri:secret:pipeforce-myservice_messaging-password"

This way, the sensitive values will be passed to your container without the requirement to store them into code or refer from external systems.

...

By default any microservice is responsible to setup and manage its own queues.

Each queue should contain always equal message types. So, for different messages, create additional queues.

...

Code Block
service_shoppingcart_orders_q

Default Topic

PIEPFORCE PIPEFORCE automatically creates a default topic exchange on startup with this name: pipeforce.hub.default.topic.

PIPEFORCE core services are configured in a way that any event which happens there or which is sent using the event.send command is will also be send to this default topic.

In case a microservice wants to listen to a certain type of message with a given routing key, it needs to create a binding between the topic pipeforce.hub.default.topic and the queue you want to “feed” this message into.

Note: The name of this default topic could change. Therefore, do not hard-code it into your microservice. Instead, use the value from the passed-in ENV variable PIPEFORCE_MESSAGING_DEFAULT_TOPIC.

See here for more details about topics, routings and queues: https://www.rabbitmq.com/tutorials/tutorial-five-python.html

...

Additionally, a default Dead Letter Queue is automatically configured by PIPEFORCE : pipeforce_hub_default_dlqthose name is given by the ENV variable PIPEFORCE_MESSAGING_DEFAULT_DLQ.

Any other queue can be configured in a way to forward messages to this queue if one these rules apply:

...

Code Block
x-dead-letter-exchange = ""
x-dead-letter-routing-key = "pipeforce_hub_default_dlq"

How to set these arguments in your microservice depends on your selected programming language and the RabbitMQ client implementation you're using. See documentation for details: https://www.rabbitmq.com/dlx.html

...

See here for more details about message key patterns on topics: https://www.rabbitmq.com/tutorials/tutorial-five-python.html

Message / Event Key

Description

delivery.created

In case a new delivery was created.

delivery.publiclink.created

In case a new public link for a delivery was created.

delivery.publiclink.deleted

In case a public link for a delivery has been deleted.

delivery.attachments.delete.success

In case the attachments of a delivery have been deleted.

delivery.attachments.delete.failed

In case the deletion of the attachments have been failed.

hub.context.started

In case hub has context has been started is ready to accept requests but right before the startup phase.

hub.context.starting

In case hub context is about to start. Note: This event is not send to the topic queue since at the time of this, the RabbitMQ connector is not setup yet. This event is just for internal use in hub. Its mentioned here just for completeness reasons.

hub.setup.finished

In case hub setup has been finished.

hub.setup.starting

In case the hub setup is about to be started. This is right after the context has been started but before the setup has been fully finished.

iam.bruteforce.detected

In case a potential bruteforce attach has been detected by IAM.

iam.login.error

In case a login using IAM has been failed.

property.copied

In case a property in the property store has been copied. See PropertyCopiedEvent.java for implementation details.

property.created

In case a property in the property store has been created. See PropertyCreatedEvent.java for implementation details.

property.deleted

In case a property in the property store has been deleted. See PropertyDeletedEvent.java for implementation details.

property.moved

In case a property in the property store has been moved. See PropertyMovedEvent.java for implementation details.

property.updated

In case a property in the property store has been moved. See PropertyUpdatedEvent.java for implementation details.

usagelog.created

A new usagelog entry was created in the property store. See UsageLogCreatedEvent.java for implementation details.

webhook.<name_of_webhook>

In case a webhook call has been occurred. The <name_of_webhook> depends on the setup. You can use the pattern webhook.# to listen to all webhooks.

Depends on key param of command event.send.

Furthermore whenever the command event.send is called, the payload of this event is also forwarded to the default hub topic using the key param of this command as the messaging key and the body as the payload of the message.