Implem / Implem.Pleasanter

Pleasanter is a no-code/low-code development platform that runs on .NET. You can quickly create business applications with simple operations.
https://pleasanter.org
GNU Affero General Public License v3.0
511 stars 81 forks source link

サーバスクリプトでのディレイ #504

Closed ebessan closed 2 months ago

ebessan commented 6 months ago

スクリプトで他のテーブルにレコードが無ければ新規でレコードを作成するものを入れています。

スクリプトに $p.events.before_send_Create もしくは $p.events.before_send_Update で実行しています。

しばらく使っていると作成漏れが発生していました。作成件数によってはクライアントの状況に依存してるかと思い、 作成後、更新後にサーバスクリプトに同じようなコードを作ってみました。

すると、レコードの作成件数が多いときは2件づつレコードが作成されるようになりました。 仮想サーバで動かしているので重いなぁと思って以下の対応を考えています。

サーバスクリプトに

    //ここから タイムディレイ
    let secondsValue = 5; //止めたい秒数
    let seconds = parseInt(secondsValue, 10) * 1000;
    let start = parseInt(new Date().getTime()) + seconds;
    while(start>parseInt(new Date().getTime())){
        // do nothing
    }
    //ここまで タイムディレイ

を追記して、setTimeoutのような動きを取り入れようかと考えました。

厳しいですかね???

pierre3 commented 6 months ago

Issueありがとうございます。 現在のところサーバースクリプトでディレイをかける手段は用意されておりません。 また、上記方法ではサーバーに負荷をかける恐れがあるため、あまりお勧めできません。

実現したい要件につきましてもう少し詳細な内容を記載いただければ、解決方法をご提示できるかもしれません。

ebessan commented 6 months ago

実現しようとしていることは、 Aテーブル Bテーブル があって、Aテーブルの作成、更新時に状況が「900」になっていた場合、Bテーブルにスクリプトで $p.events.before_send_Create もしくは $p.events.before_send_Update でレコードを作成しています。テスト運用しているとレコードの作成漏れが発生しました。 そこで、サーバスクリプトの「作成後」「更新後」にチェックをいれて、同じ内容のサーバスクリプトを入れました。

想定としては、 スクリプトで「作成前」「更新前」にレコードの作成漏れがあった場合にレコードの作成をサーバサイドでしてくれるだろうと考えていました。(最初からサーバサイドで作成しようかと思ったのですが、レコード件数が多いときにエラーになってしまいます。タイムアウト時間を長くすると、それはそれで利便性が悪いので大部分はスクリプトで処理して不足分のみサーバスクリプトで処理してほしいと考えました。)

結果は、うまくいくときもありますが、レコードが2件づつ作成される場合がありました。そこで、ディレイをかければタイミングをずらせれるかと考えて、上記の方法を検討していました。(ご指摘の通り、負荷が大きそうなのでまだテストしていません。)

入れているスクリプトは単純に↓の通りです。 (スクリプト)

for (let i= 0; i < $Sagyoin.length; i++) {
    $p.apiGet({
        id: (Bテーブルid),
        data: {
            'ApiKey': '',
            'View': {
                'ColumnFilterHash': {
                    'ClassA': '[' + $Sagyoin[i] + ']',
                    'ClassZ': '[' + $p.id() + ']'
                }
            }
        }, 
        done: function(data) {
            $p.setMessage('#Message', JSON.stringify({
                Css: 'alert-success',
                Text: '処理中。。。。。'
            }));            
            if (data.Response.Data.length == 0) {
                $p.apiGet({
                    id: $Sagyoin[i],
                    data: {
                        'ApiKey': '',
                    },
                    done: function(data) {
                        $p.apiCreate({
                            id: (Bテーブルid),
                            data: {
                                ClassHash: {
                                    ClassA: data.Response.Data[0].ResultId,
                                    ClassC: data.Response.Data[0].ClassHash.ClassC,
                                    ClassD: $StTime,
                                    ClassE: $EnTime,
                                    ClassZ: $p.id()
                                },
                                NumHash: {
                                    NumB: data.Response.Data[0].NumHash.NumB,
                                    NumE: $Nissuu
                                },
                                DateHash: {
                                    DateA: $p.getControl('StartTime').val(),
                                    DateB: $p.getControl('CompletionTime').val()
                                },
                            },
                            done: function() {
//                                          console.log('OK Create Record');
                            },
                            fail: function() {
//                                          console.log('Fail Create Record');
                            },
                            always: function(){
                            }
                        });
                    },
                    fail: function() {
                    }

                });
            } else {
                $p.apiUpdate({
                    id: data.Response.Data[0].ResultId,
                    data: {
                        ClassHash: {
                            ClassD: $StTime,
                            ClassE: $EnTime
                        },
                        NumHash: {
                            NumE: $Nissuu
                        },
                        DateHash: {
                            DateA: $p.getControl('StartTime').val(),
                            DateB: $p.getControl('CompletionTime').val()
                        },
                    },
                    done: function() {
//                                  console.log('OK Update Record');
                    },
                    fail: function() {
//                                  console.log('Fail Update Record');
                    },
                    always: function(){
                    }
                }); 
            };
        },
        fail: function() {
        }
    });
};

↓サーバスクリプトにいれているものです。 (サーバスクリプト、作成後・更新後にチェック)

for (let i= 0; i < Sagyoin.length; i++) {
    let data = {
        "View": {
            "ColumnFilterHash": {
                "ClassZ": "[" + model.IssueId + "]",
                "ClassA": "[" + Sagyoin[i] + "]"
            }
        }
    };
    let CountData = items.Count((Bテーブルid), JSON.stringify(data));
    if (CountData == 0) {
        let GetData = items.Get(Sagyoin[i]);
        let Ndata = items.NewResult();
        Ndata.ClassA = GetData[0].ResultId;
        Ndata.ClassC = GetData[0].ClassC;
        Ndata.ClassD = StTime;
        Ndata.ClassE = EnTime;
        Ndata.ClassZ = model.IssueId;
        Ndata.NumB = GetData[0].NumB;
        Ndata.NumE = Nissuu;
        Ndata.DateA = Sekokaishibi.getFullYear() + "/" + (Sekokaishibi.getMonth() + 1) + "/" + Sekokaishibi.getDate();
        Ndata.DateB = Sekokanryobi.getFullYear() + "/" + (Sekokanryobi.getMonth() + 1) + "/" + Sekokanryobi.getDate();
        items.Create((Bテーブルid), Ndata);

    };
};
pierre3 commented 5 months ago

大変お待たせいたしました。

コードを確認しましたところ下記のような処理を行っているとお見受けいたしました。

  1. テーブルBで条件に合うレコードを検索
  2. レコードが存在したらアップデート
  3. レコードが存在しなかったら新規作成 この方法ですと、1.と2,3の間でレコードの状況が変わるなど、タイミングによっては意図通りに動かないケースがあります。

上記1~3を一度に実行するUpsertというAPIがございます。 こちらを利用した実装を検討してみてください。

開発者向け機能:API:テーブル操作:レコード作成・更新 https://pleasanter.org/manual/api-record-upsert

github-actions[bot] commented 3 months ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.

github-actions[bot] commented 2 months ago

This issue was closed because it has been stalled for 7 days with no activity.