Fallback manifests

When OpenFin platform applications run on non-managed desktops, it may be challenging for a platform provider to know what OpenFin Runtime versions are available on the desktop. On a non-managed desktop it is possible that no desktop owner settings have been applied. When the platform provider specifies a new Runtime version in the application manifest for an upgrade, the new version might not be present on the targeted desktop; the RVM must retrieve the necessary assets from OpenFin's CDN. In some rare cases, the ability to reach OpenFin's CDN might be hindered due to factors such as proxy configurations, anti-virus systems, or Windows policies that block binary downloads.

To address these situations, platform providers can specify multiple OpenFin Runtime version that their software has been tested with, so that their platform can use an alternative version if the preferred version is not available. This functionality is supported in RVM version 9 and later.

Make a manifest fallback list

In the application manifest file, include a fallbackManifests top level setting, which is a list of objects with the "manifest" member set to a string that is the URL of a fallback manifest. This scheme assumes that each fallback manifest specifies a runtime.version value that is compatible with the application.

The following is an example of an application manifest containing a manifest fallback list:

{
  "startup_app": {
    "name": "APPLICATION_NAME",
    "url": "https://EXAMPLE_DOMAIN.com/APPLICATION_NAME",
    "uuid": "APPLICATION_UUID"
  },
  "runtime": {
    "arguments": "--RUNTIME_ARGUMENT1 --RUNTIME_ARGUMENT2",
    "version": "PREFERRED_RUNTIME_VERSION"
  },
  "fallbackManifests": [
    {
      "manifest": "FALLBACK_MANIFEST_URL_1"
    },
    {
      "manifest": "FALLBACK_MANIFEST_URL_2"
    },
    ...
  ]
}

How manifest fallback lists work

A manifest fallback list is used only when an application is launched using fin.System.launchManifest(). It is ignored in other starting scenarios.

When the RVM reads and evaluates the initial application manifest (called the launched manifest), if the application fails to start for any reason, the RVM begins evaluating the fallback manifests, in the order they are listed. For each listed fallback manifest, the RVM performs an assessment to determine whether the manifest can be used. The assessment looks at the following factors:

  • The URL is a valid web URL or local file path.
  • The RVM can create an app using the URL.
  • The Runtime version number in the fallback manifest can be resolved.
  • The fallback manifest's Runtime version is already installed, or if it is not installed, the RVM checks the following:
    • The runtime version is available for download.
    • The RVM can write to the Runtime installation directory.
    • If the preceding checks are OK, the RVM attempts to download and install the Runtime version specified in the fallback manifest.

If any of the checks fail, the RVM closes the app it was attempting to start and removes any Runtime it installed. It then moves on to assess the next fallback manifest in the list. Once a fallback manifest successfully starts the application, the rest of the fallback manifests in the list are ignored. If none of the fallback manifests can be used, the launch of the application fails with an error message to the end-user. It can also fail if there was a fatal error during the execution of the checks.

Progress events

There is no user interface shown while fallback manifests are being checked, which can take noticeable time. In Runtime version 29 and later, you can use the opts parameter of fin.System.launchManifest to subscribe to events related to the fallback manifest evaluation process. The following code example shows a basic way to do this.

fin.System.launchManifest("%LAUNCHED_MANIFEST_URL%", {
    subscribe: (launch) => {
        launch.on('app-version-progress', (progress) => {
            console.log(JSON.stringify(progress, null, 2));
        });
        launch.on('runtime-status', (progress) => {
            console.log(JSON.stringify(progress, null, 2));
        })
        launch.on('app-version-complete', (progress) => {
            console.log(JSON.stringify(progress, null, 2));
        })
        launch.on('app-version-error', (progress) => {
            console.log(JSON.stringify(progress, null, 2));
        })
    }
});

The following events are emitted during the fallback manifest resolution process:

  • Progress: Emitted before each fallback manifest URL is assessed.
  • Error: Emitted as the last event if the resolution process fails.
  • Complete: Emitted as the last event if the resolution process succeeds.
  • Runtime status: Emitted after each fallback manifest URL is assessed.

The Progress, Error, and Complete events contain the following fields:

FieldDescriptionProgress eventError eventComplete event
typeType of the eventapp-version-progressapp-version-errorapp-version-complete
srcManifestLaunched manifest URLYYY
manifestURL of manifest being assessedYN (does not refer to a specific manifest)Y
errorDescription of the errorNYN

The Runtime status type of event has the following fields:

  • error: a description of the problem with the manifest or null if there is no error.
  • exists: whether the Runtime version is installed, or null if it was not checked.
  • healthCheck: whether the Runtime version passes the health check, or null if it was not checked.
  • reachable: whether the specified manifest is reachable and downloadable, or null if it was not checked.
  • type: runtime-status
  • version: the Runtime version being checked for.
  • writeAccess: whether the Runtime installation directory is writable, or null if it was not checked.

Log entries for version resolution

In addition to emitting the version resolution events that your code can subscribe to, the RVM (version 9 and later) writes entries to the RVM log related to the version resolution process. You can view the RVM log as a way to determine what happened during a version resolution process, even when your code did not subscribe to the events. The following log entries are examples of what is logged in various scenarios.

Bad runtime version

// The launched manifest has a broken runtime version "thisWontWork"; it fails to start
22-11-04 20:45:33.870 | 30292:36436 | ERROR | GENERAL | Unable to determine valid runtime version number from release channel URL: https://cdn.openfin.co/release/runtime/thisWontWork
22-11-04 20:45:33.871 | 30292:36436 | ERROR | GENERAL | The specified runtime version wasn't a release channel, or a valid version: thisWontWork
22-11-04 20:45:33.900 | 30292:22004 | INFO | APP_REGISTRY | http://127.0.0.1:9070/appp.json?version=thisWontWork: Loading -> Failed [Unable to resolve runtime version using the supplied assets URL: https://cdn.openfin.co/release/ and runtime version: thisWontWork]
22-11-04 20:45:33.902 | 30292:22004 | INFO | APP_REGISTRY | Removed 'http://127.0.0.1:9070/appp.json?version=thisWontWork'

Evaluating fallback manifests

// Fallback URL iteration starts
22-11-04 20:45:33.960 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Created
22-11-04 20:45:34.015 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Fallback manifests obtained, using assets URL: 'https://cdn.openfin.co/release/'

// Fallback manifests listed
22-11-04 20:45:34.016 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] http://127.0.0.1:9070/appp.json?version=wrong
22-11-04 20:45:34.017 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] http://127.0.0.1:9070/appp.json?version=30.107.73.16
22-11-04 20:45:34.017 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] http://127.0.0.1:9070/appp.json?version=stable-v26
22-11-04 20:45:34.019 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Starting
22-11-04 20:45:34.021 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Trying next manifest URL
22-11-04 20:45:34.022 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Trying URL 'http://127.0.0.1:9070/appp.json?version=wrong'
22-11-04 20:45:34.025 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Sending status message: {"action":"app-version-progress","appVersionId":"262a38ab-03cd-453b-b7bc-3a1d8afed6b5","manifest":"http://127.0.0.1:9070/appp.json?version=wrong","srcManifest":"http://127.0.0.1:9070/appp.json?version=thisWontWork"}
22-11-04 20:45:34.046 | 30292:22004 | INFO | VERBOSE | QueueOutgoingMessage: [PendingRequest ID:2;attempt:0;duration:00:00:00.015999;->0x002407AC;[FromRvmMessage [*] system/app-version-progress:95e7dafa-8dbe-435a-aaeb-1e4de57a547e]]
22-11-04 20:45:34.094 | 30292:22004 | INFO | VERBOSE | ::SendMessageTimeout() finished: 0x00781884 -> 0x002407AC, took  0.000056s wall, 0.000000s user + 0.000000s system = 0.000000s CPU (n/a%)
 sendResult = 1 message={"broadcast":true,"messageId":"95e7dafa-8dbe-435a-aaeb-1e4de57a547e","payload":{"action":"app-version-progress","appVersionId":"262a38ab-03cd-453b-b7bc-3a1d8afed6b5","manifest":"http://127.0.0.1:9070/appp.json?version=wrong","srcManifest":"http://127.0.0.1:9070/appp.json?version=thisWontWork"},"topic":"system"}
22-11-04 20:45:34.112 | 30292:22004 | INFO | VERBOSE | TrySendMessage: Request sent OK: [PendingRequest ID:2;attempt:0;duration:00:00:00.081999;->0x002407AC;[FromRvmMessage [*] system/app-version-progress:95e7dafa-8dbe-435a-aaeb-1e4de57a547e]]

Evaluating successive manifests

// First manifest assessment failed
22-11-04 20:45:35.303 | 30292:22004 | WARNING | FALLBACK_RESOLVER | [1] Not able to resolve runtime version 'wrong'
22-11-04 20:45:35.305 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Sending status message: {"action":"runtime-status","appVersionId":"262a38ab-03cd-453b-b7bc-3a1d8afed6b5","error":"Not able to resolve runtime version 'wrong'","exists":null,"healthCheck":null,"reachable":null,"version":"wrong","writeAccess":null}
22-11-04 20:45:35.465 | 30292:22004 | INFO | VERBOSE | TrySendMessage: Request sent OK: [PendingRequest ID:4;attempt:0;duration:00:00:00.066000;->0x002407AC;[FromRvmMessage [*] system/app-version-progress:c2e3c284-825f-4384-b26e-253164b189ca]]
…

// Next iteration
22-11-04 20:45:35.393 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Trying next manifest URL
22-11-04 20:45:35.393 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Trying URL 'http://127.0.0.1:9070/appp.json?version=30.107.73.16'
22-11-04 20:45:36.304 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Checking runtime version '30.107.73.16'
22-11-04 20:45:36.305 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Trying to install runtime '30.107.73.16'

Installing and checking a Runtime version

// HTTP HEAD for the runtime version
22-11-04 20:45:36.306 | 30292:22004 | INFO | NETWORK | Head request for url: "https://cdn.openfin.co/release/runtime/30.107.73.16"
22-11-04 20:45:36.307 | 30292:22004 | INFO | NETWORK | Processing url: "https://cdn.openfin.co/release/runtime/30.107.73.16"
22-11-04 20:45:36.979 | 30292:30812 | INFO | GENERAL | Installing runtime from url: "https://cdn.openfin.co/release/runtime/x64/30.107.73.16"
22-11-04 20:45:45.321 | 30292:30812 | INFO | VERBOSE | Moving the runtime files downloaded to temp to their final location: "E:\clones\rvm6\out\build\x86-debug-vs2013-notests\OpenFinRVM\OpenFinRVM\Debug\runtime\30.107.73.16\OpenFin"
22-11-04 20:45:45.850 | 30292:30812 | INFO | GENERAL | Installed runtime: 30.107.73.16
22-11-04 20:45:45.933 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Runtime installation '30.107.73.16' complete in '"E:\clones\rvm6\out\build\x86-debug-vs2013-notests\OpenFinRVM\OpenFinRVM\Debug\runtime\30.107.73.16\OpenFin"' Minimal runtime healthcheck version: 29.0.0.0

// Starting the app from the fallback manifest on the freshly installed runtime
22-11-04 20:45:45.934 | 30292:22004 | INFO | APP_REGISTRY | Added 'http://127.0.0.1:9070/appp.json?version=30.107.73.16'
22-11-04 20:45:45.935 | 30292:22004 | INFO | APP_REGISTRY | http://127.0.0.1:9070/appp.json?version=30.107.73.16: Created -> Created [NO ERROR]
22-11-04 20:45:45.936 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] App 'http://127.0.0.1:9070/appp.json?version=30.107.73.16' -> Created
22-11-04 20:45:45.936 | 30292:22004 | INFO | APP_REGISTRY | http://127.0.0.1:9070/appp.json?version=30.107.73.16: Created -> Loading [NO ERROR]
22-11-04 20:45:45.937 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] App 'http://127.0.0.1:9070/appp.json?version=30.107.73.16' -> Loading
22-11-04 20:45:45.938 | 30292:22004 | INFO | GENERAL | Added app to load queue: http://127.0.0.1:9070/appp.json?version=30.107.73.16, origin: FallbackResolverManifestAssesment
22-11-04 20:45:46.708 | 30292:22004 | INFO | APP_REGISTRY | http://127.0.0.1:9070/appp.json?version=30.107.73.16: Loading -> Loaded [NO ERROR]
22-11-04 20:45:46.709 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] App 'http://127.0.0.1:9070/appp.json?version=30.107.73.16' -> Loaded

// Runtime health check request to core is sent
22-11-04 20:45:46.710 | 30292:22004 | INFO | HEALTHCHECK_REQUEST_MAKER | PerformRequest 'http://127.0.0.1:9070/appp.json?version=30.107.73.16'
22-11-04 20:45:46.710 | 30292:22004 | INFO | GENERAL | Successfully loaded the app: http://127.0.0.1:9070/appp.json?version=30.107.73.16
22-11-04 20:45:46.739 | 30292:22004 | INFO | RUNTIME_MANAGER | Runtime '30.107.73.16' -> Started
22-11-04 20:45:47.644 | 30292:22004 | INFO | APP_REGISTRY | http://127.0.0.1:9070/appp.json?version=30.107.73.16: Loaded -> Started [NO ERROR]

// RVM Message Bus endpoint ID was found for the new app -- on Windows this is the Message Window HWND
22-11-04 20:45:47.644 | 30292:22004 | INFO | HEALTHCHECK_REQUEST_MAKER | OnEndpointIdSet: 'http://127.0.0.1:9070/appp.json?version=30.107.73.16' -> '0x00C10F02'
22-11-04 20:45:47.645 | 30292:22004 | INFO | HEALTHCHECK_REQUEST_MAKER | OnEndpointIdResolved: '0x00C10F02'
22-11-04 20:45:47.650 | 30292:22004 | INFO | VERBOSE | QueueOutgoingMessageWithResponse: 0x00C10F02 [FromRvmMessage [*] system/perform-runtime-health-check:f9182af2-2cf7-420e-96f2-9ea8f2c46025] 00:00:30
22-11-04 20:45:47.662 | 30292:22004 | INFO | VERBOSE | QueueOutgoingMessage: [PendingRequest ID:6;attempt:0;duration:00:00:00.010000;->0x00C10F02;[FromRvmMessage [*] system/perform-runtime-health-check:f9182af2-2cf7-420e-96f2-9ea8f2c46025]]
22-11-04 20:45:47.775 | 30292:22004 | INFO | APP_REGISTRY | http://127.0.0.1:9070/appp.json?version=30.107.73.16: Started -> Ready [NO ERROR]
22-11-04 20:45:47.892 | 30292:22004 | INFO | VERBOSE | ::SendMessageTimeout() finished: 0x00781884 -> 0x00C10F02, took  0.000057s wall, 0.000000s user + 0.000000s system = 0.000000s CPU (n/a%)
 sendResult = 1 message={"broadcast":true,"messageId":"f9182af2-2cf7-420e-96f2-9ea8f2c46025","payload":{"action":"perform-runtime-health-check"},"topic":"system"}
22-11-04 20:45:47.904 | 30292:22004 | INFO | VERBOSE | TrySendMessage: Request sent OK: [PendingRequest ID:6;attempt:0;duration:00:00:00.252000;->0x00C10F02;[FromRvmMessage [*] system/perform-runtime-health-check:f9182af2-2cf7-420e-96f2-9ea8f2c46025]]

// Wait for health check response from core
22-11-04 20:45:47.905 | 30292:22004 | INFO | MESSAGE_ROUTER | AddRouteByResponseToMessageId 'f9182af2-2cf7-420e-96f2-9ea8f2c46025' [00:00:30]
22-11-04 20:45:48.045 | 30292:22004 | INFO | MESSAGE_ROUTER | RouteMessage id='e52d780a-10ae-457a-82f5-1727b5c308b8' response to='f9182af2-2cf7-420e-96f2-9ea8f2c46025'
22-11-04 20:45:48.046 | 30292:22004 | INFO | MESSAGE_ROUTER | RemoveRouteByResponseToMessageId 'f9182af2-2cf7-420e-96f2-9ea8f2c46025'
22-11-04 20:45:48.048 | 30292:22004 | INFO | HEALTHCHECK_REQUEST_MAKER | OnMessageBusResponse: ID=6 from '0x00C10F02'
22-11-04 20:45:48.051 | 30292:22004 | INFO | HEALTHCHECK_REQUEST_MAKER | NotifyCallback: OK: Response item count: 2

// Response was obtained and parsed
22-11-04 20:45:48.052 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Got healthcheck response
22-11-04 20:45:48.054 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Healthcheck response item: Can launch renderer process [FAILED] 
22-11-04 20:45:48.055 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Runtime health check failed: Can launch renderer process [FAILED] 
22-11-04 20:45:48.056 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Healthcheck response item: Has read/write access to cache directory [FAILED] 
22-11-04 20:45:48.058 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Runtime health check failed: Has read/write access to cache directory [FAILED] 

// Close the app via RVM Message Bus
22-11-04 20:45:48.059 | 30292:22004 | INFO | VERBOSE | Sending close-app message for app: http://127.0.0.1:9070/appp.json?version=30.107.73.16; uuid: app_uuid_default-app-id-30.107.73.16
22-11-04 20:45:48.064 | 30292:22004 | INFO | VERBOSE | Outgoing Message to 00C10F02
    {"broadcast":true,"messageId":"49919dd1-fe9f-48c0-8d38-03e364e1ad3b","payload":{"action":"close-app","sourceUrl":"http://127.0.0.1:9070/appp.json?version=30.107.73.16","uuid":"app_uuid_default-app-id-30.107.73.16"},"topic":"application"}
22-11-04 20:45:48.077 | 30292:22004 | INFO | GENERAL | MessageDispatcher::OnMessage(): Message served by router: 0x00C10F02 [ToRvmMessage system/send-runtime-health-check:e52d780a-10ae-457a-82f5-1727b5c308b8]

// Core confirms closing the app
22-11-04 20:45:48.106 | 30292:22004 | INFO | VERBOSE | Incoming application-topic message from: 0x00C10F02; messageId: 0988b503-2beb-4f69-b7b9-52751e144e72; payload: {"action":"close-app-requested","processId":26400,"runtimeVersion":"30.107.73.16","securityRealm":"","sourceUrl":"http://127.0.0.1:9070/appp.json?version=30.107.73.16","uuid":"app_uuid_default-app-id-30.107.73.16"}
22-11-04 20:45:48.135 | 30292:22004 | INFO | APP_REGISTRY | http://127.0.0.1:9070/appp.json?version=30.107.73.16: Ready -> Closed [NO ERROR]
22-11-04 20:45:48.136 | 30292:22004 | INFO | APP_REGISTRY | http://127.0.0.1:9070/appp.json?version=30.107.73.16: Closed -> Unloaded [NO ERROR]
22-11-04 20:45:48.137 | 30292:22004 | INFO | APP_REGISTRY | Removed 'http://127.0.0.1:9070/appp.json?version=30.107.73.16'

// Runtime process finished after the app was closed
22-11-04 20:45:48.227 | 30292:22004 | INFO | RUNTIME_MANAGER | Runtime '30.107.73.16' -> Ended
22-11-04 20:45:48.228 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Runtime process '30.107.73.16' stopped

// Runtime deinstallation
22-11-04 20:45:48.301 | 30292:11180 | INFO | INSTALLATION_MANAGER | Removed 163 entries from '"E:\clones\rvm6\out\build\x86-debug-vs2013-notests\OpenFinRVM\OpenFinRVM\Debug\cache\30.107.73.16"'
22-11-04 20:45:48.303 | 30292:11180 | INFO | INSTALLATION_MANAGER | Removed '"E:\clones\rvm6\out\build\x86-debug-vs2013-notests\OpenFinRVM\OpenFinRVM\Debug\runtime\30.107.73.16\OpenFin\openfin.exe"'
22-11-04 20:45:48.371 | 30292:11180 | INFO | INSTALLATION_MANAGER | Removed 91 entries from '"E:\clones\rvm6\out\build\x86-debug-vs2013-notests\OpenFinRVM\OpenFinRVM\Debug\runtime\30.107.73.16"'
22-11-04 20:45:48.394 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Runtime removed OK
22-11-04 20:45:48.396 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Sending status message: {"action":"runtime-status","appVersionId":"262a38ab-03cd-453b-b7bc-3a1d8afed6b5","error":"Runtime health check failed: Has read/write access to cache directory [FAILED] ","exists":false,"healthCheck":false,"reachable":true,"version":"30.107.73.16","writeAccess":true}

Successful check

// Success
22-11-04 20:45:56.842 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Sending status message: {"action":"app-version-complete","appVersionId":"262a38ab-03cd-453b-b7bc-3a1d8afed6b5","manifest":"http://127.0.0.1:9070/appp.json?version=stable-v26","srcManifest":"http://127.0.0.1:9070/appp.json?version=thisWontWork"}
22-11-04 20:45:56.914 | 30292:22004 | INFO | FALLBACK_RESOLVER | [1] Finished OK 'http://127.0.0.1:9070/appp.json?version=stable-v26'
22-11-04 20:45:56.915 | 30292:22004 | INFO | APP_REGISTRY | Added 'http://127.0.0.1:9070/appp.json?version=stable-v26'
22-11-04 20:45:56.916 | 30292:22004 | INFO | APP_REGISTRY | http://127.0.0.1:9070/appp.json?version=stable-v26: Created -> Created [NO ERROR]
22-11-04 20:45:56.917 | 30292:22004 | INFO | APP_REGISTRY | http://127.0.0.1:9070/appp.json?version=stable-v26: Created -> Loading [NO ERROR]
22-11-04 20:45:56.918 | 30292:22004 | INFO | GENERAL | Added app to load queue: http://127.0.0.1:9070/appp.json?version=stable-v26, origin: FallbackResolverResult
22-11-04 20:45:58.018 | 30292:22004 | INFO | APP_REGISTRY | http://127.0.0.1:9070/appp.json?version=stable-v26: Loading -> Loaded [NO ERROR]
22-11-04 20:45:58.019 | 30292:22004 | INFO | GENERAL | Successfully loaded the app: http://127.0.0.1:9070/appp.json?version=stable-v26
22-11-04 20:45:58.049 | 30292:22004 | INFO | RUNTIME_MANAGER | Runtime '26.102.71.8' -> Started
22-11-04 20:45:58.057 | 30292:22004 | INFO | HEALTHCHECK_REQUEST_MAKER | Shutdown
22-11-04 20:45:58.058 | 30292:22004 | INFO | HEALTHCHECK_REQUEST_MAKER | Destroyed