This page explains how to prepare your cloud app for migration by processing events.
The Forge function 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 function and trigger to process migration events.
1 2modules: function: # Function to handle migration events - key: migration-fn-key handler: index.run trigger: # Migration events that will invoke your function - key: migration-trigger function: migration-fn-key events: - avi:ecosystem.migration:triggered:listener - avi:ecosystem.migration:uploaded:app_data
Our sample app provides a complete implementation.
Refer to the events API for all the events that you can listen for and their associated payloads.
Unhandled exceptions or function timeouts will result in the migration event being 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:
messageProcessed(transferId, messageId) for avi:ecosystem.migration:uploaded:app_data events
within 15 minutes of either
avi:ecosystem.migration:uploaded:app_data
may appear before avi:ecosystem.migration:triggered:listener.| Time | Event | New timeout time |
|---|---|---|
| 00:00 | Migration started by customer | 00:15 |
| 00:01 | File A uploaded by DC app | 00:16 |
| 00:01 | Event for File A received and recorded by Forge App but not yet acknowledged | 00:16 (unchanged) |
| 00:12 | File B uploaded for DC app | 00:27 |
| 00:13 | Event for File B received and recorded by Forge App but not yet acknowledged | 00:27 (unchanged) |
| 00:22 | File C uploaded for DC app | 00:37 |
| 00:22 | Event for File C received and recorded by Forge App but not yet acknowledged | 00:37 (unchanged) |
| 00:22 | Upload completed by DC app | 00:37 (unchanged) |
| 00:22 | Forge App starts processing File C (e.g. because it needs to go first) | 00:37 (unchanged) |
| 00:32 | Forge App completes processing File C and acknowledges C uploaded event | 00:47 |
| 00:33 | Forge App starts processing File A since dependency C is done | 00:47 (unchanged) |
| 00:38 | Forge App starts processing File B | 00:47 (unchanged) |
| 00:43 | Forge App completes processing File A and acknowledges A uploaded event | 00:58 |
| 00:48 | Forge App completes processing File B. It acknowledges File B and marks the transfer as SUCCESS | N/A |
Note that avoiding dependencies, and doing more importing in parallel is better than relying on a scheme like the above - but if need be sequencing processing will work, because each upload or acknowledge event occurs before the timeout.
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. |
This is the data that is passed to your Forge function when it is invoked.
| 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. |
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{ "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" }, "key": "e094ca53-3747-4541-b263-0bf7b56a5bca", "label": "file-label-you-used", "serverAppVersion": "1.0", "messageId": "53f88ea7-a2d2-4dd2-9f36-2d8c43401b11" }
Forge migration API helps you migrate your server app using your Forge app.
Import the migration API package and use its methods, for example:
1 2import { migration } from "@forge/migrations"; export function getMigrationMappings() { return migration .getMappings(transferId, "jira/classic:appCustomField") .getMany(); // => {"results":[{"key":"10004","value":"10011"}, ...]} }
The migration object contains helper functions to conduct your app migration, e.g., retrieve mappings and app data.
1 2export interface Migration { getMappingById: (transferId: string, namespace: string, keys: Array<string>) => Promise<MappingResponse>; getAppDataList: (transferId: string) => Promise<AppDataListResponse>; getAppDataPayload: (key: string) => Promise<APIResponse>; messageProcessed: (transferId: string, messageId: string) => Promise<void>; messageFailed: (transferId: string, messageId: string) => Promise<void>; getMappings: (transferId: string, namespace: string) => DefaultQueryBuilder; getContainers: (transferId: string, containerType: string) => DefaultQueryBuilder; addLog: (transferId: string, logMessage: string) => Promise<void>; } export interface MappingResponse { result: Map<string, string>; } export interface AppDataListResponse { result: Set<AppData>; } export interface AppData { s3Key: string; key: string; label: string; } export declare type APIResponse = Pick<Response, 'json' | 'text' | 'arrayBuffer' | 'ok' | 'status' | 'statusText' | 'headers'>; export interface DefaultQueryBuilder { limit(limit: number): DefaultQueryBuilder; cursor(cursor: string): DefaultQueryBuilder; getOne(): Promise<Result | undefined>; getMany(): Promise<ListResults>; } export interface Result { key: string; value: object; } export interface ListResults { results: Result[]; nextCursor?: string; } export class MigrationAPIError extends Error { status: number | undefined; message: string; }
| Name | Type | Description |
|---|---|---|
transferId | string | An ID (UUID) that the app migration platform uniquely generates per migration. |
key | string | An ID (UUID) to uniquely identify the data your server app uploads to cloud storage. |
namespace | string | Mapping namespace to fetch mappings for. |
containerType | string | Type of container, valid values are ConfluenceSpace, JiraProject, Site. |
keys | Array<string> | List of server keys to query for. |
messageId | string | An ID (UUID) to uniquely identify Forge event for the app migration platform. |
logMessage | string | Message to display to customers that will be visible in progress logs. |
Any non-200 response status will result in the function throwing MigrationAPIError. You can handle it like so:
1 2import { migration, MigrationAPIError } from '@forge/migrations' function getMigrationMappings() { return migration.getMappings(transferId, namespace) .getMany() .catch((error) => { if (error instanceof MigrationAPIError && error.status !== undefined) { console.error('Unexpected status code', error.status) } else { console.error('Something went wrong') } }) }
This documentation has moved. See REST API documentation instead.
Rate this page: