[ODC]On Application Ready動作タイミングを実地に確認してみる

アプリケーション開始時に発生するシステムイベントがApplication Ready。
実際の動作タイミングを実地に確認してみる。

# 環境情報
ODC Studio(Version 1.5.2)

# On Application Readyとは
アプリケーション開始時に発生するSystem Event。このEventに対するハンドラーで、各種変数の初期設定などを行う。
ドキュメントはこちら：[On Application Ready - ODC Documentation](https://success.outsystems.com/documentation/outsystems_developer_cloud/building_apps/application_logic/on_application_ready/)

OutSystems 11の頃は、途中まではOn Application Readyは非同期に実行され、Version 11.16.1からは同期に実行されるように変更された。
同期に実行されるとは、この場合、On Application Readyの完了までUIの描画がブロックされるということ。

↓はドキュメントの履歴から、いつ非同期→同期に帰られたタイミングを確認できるもの。

https://github.com/OutSystems/docs-product/commit/d6992a29f9c7f9f1e7fe798df6ac0e2c53632da0

実際、On Application ReadyにJavaScript要素を配置し、数億回無駄にループさせる（ちょっと時間がかかる）と、ループが完了されるまで画面は表示されない。

## On Begin Web Requestとは何が違う？
最近OutSystemsを始めた人は聞いたことがないかもしれないが、古いWebアプリケーション開発には、Traditional Webという種類のモジュールを使っていた。

Traditonal WebはSPAではなく、より古い方式のWebアプリケーション開発方法。System EventとしてBegin Web Requestがあり、これはWebリクエスト（ページアクセスやUI操作による）の最初に動く。このため、各リクエストに共通する初期処理を書けた。

これに対し、Application Readyは、ブラウザへの最初のアプリケーションロード時に発生する。

# イベントハンドラー作成方法
Applcation Readyはクライアントで発生するイベントなので、ハンドラーはClient Actionとして作成する。

Logicタブ > Client Actionsを右クリック > Add System Event > On Application Ready
と選んでいくと、Client Actions直下にハンドラーが作成される。
![スクリーンショット 2025-01-16 21.56.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/0dd6c3f1-8539-b430-6a0e-7c8570398aab.png)

## この記事中での動作確認方法：JavaScript要素でconsole.logして、ブラウザの開発者ツール > Consoleを確認

イベントハンドラ中にJavaScript要素を配置し、
![スクリーンショット 2025-01-19 16.03.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/d9660d00-4596-20b6-98f5-e69aa6652bd1.png)

JavaScriptコードは以下の通り、シンプルにコンソールに日時付きでログを出力するもの。
``` js
console.log('On Application Ready' + (new Date()));
```

これで、On Application Readyが動作すると、ブラウザの開発者ツール > Consoleタブにログが出力される（以下はChromeの例）。

![スクリーンショット 2025-01-19 16.06.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/af10d966-d5ff-d1bc-d92a-854dd9f0a0e3.png)

# 画面遷移の検証
以下の様々なパターンで画面遷移させてみて、Consoleログの出力有無でOn Application Readyが動作するかを確認する。
## 同じAppのScreen間で通常の画面遷移：Application Readyは発生しない
以下の実装パターンでは、遷移先の画面を開く際に、Application Readyイベントは発生しないようだ。

- ButtonのOn Clickに直接画面を指定する
- ButtonのOn ClickにClient Actionを指定し、その中で画面を指定したDestinationを配置
- ButtonのOn ClickにClient Actionを指定し、その中で画面の相対パスへのRedirectoToURLを指定したDestinationを配置
- LinkのOn Clickに直接画面を指定する
- ブラウザの戻る/進む操作

## JavaScriptで画面遷移する場合：Application Readyは発生する
例えば、以下のコードを配置したJavaScript要素を利用した場合 (同じAppのNavigation2 Screemに遷移する）。

``` js
location.href = "Navigation2";
```

## アドレスバーでEnter押したり、直接貼り付けたら：同じ画面であってもApplication Readyは発生する
これは、画面を表示している状態で、ブラウザのアドレスバーを変更せずEnterキーを叩いたり、ブックマークから開いたり、URLをアドレスバーに貼り付けた場合。

これは、ドキュメントにも記載がある（ブラウザのページ更新でも同じようだ）。
> Note that if the user types or refreshes the URL of a screen directly in the browser address bar, On Application Ready is executed. 

## 時間を置いてから画面遷移した：2時間程度では画面遷移してもApplication Readyは発生しなかった
一度画面を表示し、2時間ほど放置してから同じAppの別画面へ遷移させてみた。
この時、Application Readyは発生しなかった。
ただし、ODCのApplicationはSPAであることから、ブラウザのメモリにいろいろ載っており、それを前提に初期ロードが必要か判定しているはず。つまり、何からの理由でメモリから対象部分が失われていればApplication Readyが発生するかもしれないので注意。

## 他Appを開き、画面参照やRedirectToURLで戻ってくる：Application Readyは発生しない
App1とApp2があるとき、
- App1からDestinationを使ってApp2へ遷移
- ①App2からApp1のScreenを参照し、App2上からButtonクリック時に参照したScreenへ遷移させる
- ②App2上からButtonクリック時にApp1のScreenへサーバーからの相対パスで遷移させる

①②共に、On Application Readyは動作しなかった。

# その他の技術的事項
## ネットワーク処理を含めるとOn Application Readyが非同期になる
時間のかかるServer Actionを呼んでみたら、非同期に動いた（On Application Ready終了を待たずにUIが表示された）。
これは、恐らくClient Actionにサーバー処理を含めると非同期に動作するという仕様のため。

https://success.outsystems.com/documentation/11/integration_with_external_systems/javascript/defining_asynchronous_javascript_code/#define-an-asynchronous-client-action

> if a given client action contains server calls, like executing server actions or refreshing aggregates, this will also make the client action to be considered asynchronous.

## On Application Readyで発生した例外はGlobal Exception Handlerでは補足できない
On Application ReadyにRaise Exceptionを配置し、かつException Handlerを配置しないと、以下のエラーメッセージのみが表示される（本来のUIは全く表示されない）。

> There was an error processing your request.

これは、未捕捉の例外があるため。

https://success.outsystems.com/documentation/outsystems_developer_cloud/building_apps/handling_exceptions/exception_handling_mechanism/

に記載がある。Global Exception Handlerで捕捉されないということは、On Application Readyで例外発生の可能性があるときは、当Action自身で確実にException Handlerを配置する必要があるということ。
> OnApplicationReady is a special event handler that is not covered by the Global Exception Handler. For that reason, error handling should be implemented in the action itself.

# 関連：OutSystems11の時に動作確認した時の記事
https://qiita.com/jyunji_watanabe/items/7ef1dc8fe23dc76018d8

# 実装方針案
上記を踏まえると、以下の方針がよさそう。

- On Application Readyでは通信や長時間実行される処理は行わない
- Exception HandlerでAll Exceptionsを捕捉する

「画面リクエストごとに必要な処理は、On Application Readyでは行えない」
→Traditional WebのOnBeginWebRequestの代わりには使えないという点にも注意。