This page explains how to prepare your cloud app for migration by processing events.
Forge container services is in Preview. Migration support for Forge container services follows the same status.
The Forge container service, endpoint, and trigger modules that you implement will allow the app migration platform to send information about specific migration events that take place on your server app.
Define a service, an endpoint, and a trigger to process migration events.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28modules: trigger: - key: migration-trigger endpoint: migration-event events: - avi:ecosystem.migration:triggered:listener - avi:ecosystem.migration:uploaded:app_data ... endpoint: - key: migration-event service: migration-service route: path: /migration-events services: - key: migration-service containers: - key: migration-container tag: ${TAG} resources: cpu: "1" memory: "2Gi" health: type: http route: path: /health
The app migration platform sends each event to your container service as an HTTP POST request to the endpoint route.path.
Refer to the event types for all the events that you can listen for and their associated payloads.
If your container service returns an invalid response the migration event will be sent again with exponential backoff up to four times for a total of five attempts.
When processing events it is important to keep in mind the following:
avi:ecosystem.migration:uploaded:app_data events
within 15 minutes of processing the last event or uploading new data from the server app (whichever occurs later).avi:ecosystem.migration:uploaded:app_data
may appear before avi:ecosystem.migration:triggered:listener.If you are migrating from Connect and are finding it difficult to ensure you acknowledge an event or upload new data every 15 minutes without a major rewrite of your migration logic, please contact Ecosystem Support; we have some additional temporary options available (subject to approval and periodic review of your use case by Atlassian) to support migrations until you are able to progressively import and acknowledge data.
You can add the following events to your Forge trigger.
| Event | Description |
|---|---|
avi:ecosystem.migration:triggered:listener | Your server app migration listener has been triggered. |
avi:ecosystem.migration:uploaded:app_data | Your server app uploaded app data. |
avi:ecosystem.migration:requested:transfer_cancellation | The user has cancelled a transfer. |
avi:ecosystem.migration:errored:listener | An unhandled exception occurred in your server app migration listener. |
avi:ecosystem.migration:completed:export_phase | completeExport() has been called in your server app to signal to your Forge app that all app data has been uploaded. |
avi:ecosystem.migration:settled:transfer | The app migration platform has settled the transfer. |
avi:ecosystem.migration:uploaded:key_value_pair | Your server app uploaded key value pair data. |
avi:ecosystem.migration:uploaded:sql_data | Your server app uploaded SQL data data. |
avi:ecosystem.migration:preloaded:app_data | Your server app has preloaded data. |
This is the data that is sent in the body of the request to your container service endpoint.
| Attribute | Type | Description |
|---|---|---|
eventType | string | The migration event type. |
transferId | string | An ID (UUID) that the app migration platform uniquely generates per migration. |
migrationDetails.migrationId | string | An ID (UUID) that the app migration platform uses to uniquely identify a migration. |
migrationDetails.migrationScopeId | string | An ID that the app migration platform generates to uniquely determine a source (server) and destination (cloud-site) of migration. |
migrationDetails.createdAt | number | Timestamp of when the app migration was created. |
migrationDetails.cloudUrl | string | URL of the destination cloud site for the migration. |
migrationDetails.name | string | The name of the migration plan provided by the user who initiated the migration. |
migrationDetails.testMigration | boolean | undefined | Whether the migration is a test migration. This optional field may be present on Forge migration events. |
serverAppVersion | string | undefined | The version of the server app. This optional field is present on avi:ecosystem.migration:triggered:listener events. |
key | string | An ID (UUID) to uniquely identify the data your server app uploads to cloud storage. This will only be present on avi:ecosystem.migration:uploaded:app_data events. |
label | string | undefined | Metadata that provides additional information about the data your server app uploads to cloud storage. This will only be present on avi:ecosystem.migration:uploaded:app_data events. |
messageId | string | An ID (UUID) that the app migration platform generates to uniquely recognise an event. |
transferError.exceptionType | string | undefined | Metadata that provides details of the exception type that occurs when executing server side listener method (onStartAppMigration). This will only be present on avi:ecosystem.migration:errored:listener events. |
transferError.safeStackTrace | string | undefined | Metadata that provides the stack trace of error that occurs when executing server side listener method (onStartAppMigration). This will only be present on avi:ecosystem.migration:errored:listener events. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17{ "eventType": "avi:ecosystem.migration:uploaded:app_data", "transferId": "3f3a47f2-a6a2-4204-84bb-d0fc504c9dc6", "migrationDetails": { "migrationId": "403c4f71-a0d1-4a63-97a8-487d18691c46", "migrationScopeId": "0ba07dd9-3804-4600-9102-fa6e1efeab08", "createdAt": 1723111376499, "cloudUrl": "https://your-customer-cloud-site.atlassian.net", "name": "Migration Plan Name", "testMigration": false }, "key": "e094ca53-3747-4541-b263-0bf7b56a5bca", "label": "file-label-you-used", "serverAppVersion": "1.0", "messageId": "53f88ea7-a2d2-4dd2-9f36-2d8c43401b11" }
Refer to the REST API documentation for the available endpoints and their usage.
Your container service does not call https://api.atlassian.com directly. Send requests to the egress sidecar
using the URL in the FORGE_EGRESS_PROXY_URL environment variable. Prefix the API paths in the REST API documentation with /atlassian, for example /atlassian/app/migration/forge/v1/message/{transferId}/status.
Requests to the egress sidecar must contain a forge-proxy-authorization header. Use as=app for all app migration platform requests. There are two ways to identify the context of the request:
| Option | Header | When to use |
|---|---|---|
| Invocation ID | forge-proxy-authorization: Forge as=app,id=<x-forge-invocation-id> | While you are handling the request that delivered the event. Use the x-forge-invocation-id header from the inbound request. |
| Installation ID | forge-proxy-authorization: Forge as=app,installationId=<installationId> | When you process data after the event request has completed, for example in a background job or a queue worker. Retrieve the ID using the Get app installations endpoint. |
For more detail, refer to Forge Container services API contract and Call a containerised service without an invocation ID.
The Forge Container services sidecar authenticates inbound requests to your service, so you do not need to verify the requests yourself.
The following example handles every event sent to the endpoint, and acknowledges only avi:ecosystem.migration:uploaded:app_data events after processing them. It is an excerpt, and uses Node.js with Express.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42import express from "express"; const app = express(); app.use(express.json()); app.post("/migration-events", async (req, res) => { const event = req.body; const invocationId = req.header("x-forge-invocation-id"); // Validate the payload and process the event if (!event.transferId || !event.messageId) { return res.status(400).json({ error: "Invalid migration event" }); } // Only uploaded app data needs to be acknowledged. Return 200 for all other event types. if (event.eventType !== "avi:ecosystem.migration:uploaded:app_data") { return res.json({ message: `Ignored ${event.eventType}` }); } // ... download and import the data identified by event.key ... const response = await fetch( `${process.env.FORGE_EGRESS_PROXY_URL}/atlassian/app/migration/forge/v1/message/${event.transferId}/status`, { method: "POST", headers: { "Content-Type": "application/json", "forge-proxy-authorization": `Forge as=app,id=${invocationId}`, }, body: JSON.stringify({ status: "SUCCESS", messageIds: [event.messageId] }), } ); if (!response.ok) { // A non-2xx response will cause the event to be sent again return res.status(502).json({ error: `Status update failed: ${response.status}` }); } return res.json({ message: `Successfully processed ${event.messageId}` }); }); app.listen(process.env.SERVER_PORT);
It is important for building reliable migration paths to retry on 5xx and 429 errors for all API calls with exponential backoff and jitter.
Rate this page: