js / node.jsのステロイドテレパシー

画像 製品サポートフェーズには多くのエネルギーと神経が必要です。 「私は押すがうまくいかない」から問題を解決する方法、一流のテレパスであっても、多くの時間がかかります。 クライアント/ボスが怒って不満を感じる時間。



問題を解決するための時間を短縮するには、エラーをすばやく見つけて、原因をできるだけ正確に把握し、できればすべてをまとめて収集する必要があります。



カットの下での私の決定についてお話しします。


1.目的



議論の後、クライアントとサーバーからエラー情報を収集し、後続の応答のためにデータを転送または処理できるメカニズムを作成することにしました。 このメカニズムにより、将来、コードを不必要に書き換えることなくデータを操作する方法を追加し、構成から作業方法、順序などを変更できるようにする必要があります。



キーポイント:



2.決定



サーバーの起動時に、特別なエラーハンドラーを読み込むことが決定されました。ドライバーは、構成から順番と優先順位が読み込まれます。 フロントエンドのエラーはサーバーに送信され、そこで残りと一緒に処理されます。



主なアイデアは、エラーが発生し、スタックがグローバルエリアに巻き戻されると、分散コレクターを使用してエラークラスにデバッグ情報が追加されるということです。 グローバルエリアに該当する場合、エラーはエラードライバーを使用してインターセプトおよび処理されます。



2.1エラークラス



カスタムエラークラスが標準から継承されました。 コンストラクターがエラーを受け入れ、「アラームレベル」を指定してデバッグデータを追加する機能。 このクラスは、フロントエンドファイルとバックエンドファイル用の単一のツールにあります。



以降、コードはライブラリco、socket.io、sugar.jsを使用しました

フルクラスコード
app.Error = function Error(error,lastFn){ if(error && error.name && error.message && error.stack){ ,       this.name=error.name; this.message=error.message; this.stack=error.stack; this.clueData=error.clueData||[]; this._alarmLvl=error._alarmLvl||'trivial'; this._side=error._side || (module ? "backend" : "frontend");//  return; } if(!app.isString(error)) error='unknown error'; this.name='Error'; this.message=error; this._alarmLvl='trivial'; this._side=module ? "backend" : "frontend"; this.clueData=[]; if (Error.captureStackTrace) { Error.captureStackTrace(this, app.isFunction(lastFn)? lastFn : this.constructor); } else { this.stack = (new Error()).stack.split('\n').removeAt(1).join();//       } }; app.Error.prototype = Object.create(Error.prototype); app.Error.prototype.constructor = app.Error; app.Error.prototype.setFatal = function () {//getter/setters    this._alarmLvl='fatal'; return this; }; app.Error.prototype.setTrivial = function () { this._alarmLvl='trivial'; return this; }; app.Error.prototype.setWarning = function () { this._alarmLvl='warning'; return this; }; app.Error.prototype.getAlarmLevel = function () { return this._alarmLvl; }; app.Error.prototype.addClueData = function(name,data){//   var dataObj={}; dataObj[name]=data; this.clueData.push(dataObj); return this; };
      
      







Promiseの使用例:



 socket.on(fullName, function (values) { <...> method(values)//  api .then(<...>) .catch(function (error) {//  throw new app.Error(error)//         .setFatal()// " " .addClueData('api', {//   fullName, values, handshake: socket.handshake }) }); });
      
      





try-catchについても同じことを行います。



2.2フロントエンド



フロントエンドの場合、問題は、トランスポートライブラリ(この場合はsocket.io)が読み込まれる前でもエラーが発生する可能性があることです。



この問題を回避するには、一時変数にエラーを収集します。 グローバルスコープからエラーをインターセプトするには、window.onerrorを使用します。



 app.errorForSending=[]; app.sendError = function (error) {//     app.io.emit('server error send', new app.Error(error)); }; window.onerror = function (message, source, lineno, colno, error) {//     app.errorForSending.push(//    . new app.Error(error) .setFatal());//    ,       }; app.events.on('socket.io ready', ()=> {//    window.onerror = function (message, source, lineno, colno, error) {//  app.sendError(new app.Error(error).setFatal()); }; app.errorForSending.forEach((error)=> {//  ,   app.sendError(error); }); delete app.errorForSending; }); app.events.on('client ready', ()=> {//      window.onerror = function (message, source, lineno, colno, error) { app.sendError(error); }; });
      
      





一部のライブラリでは、エラーをスローせず、コンソールに印刷するのが面倒なだけであるという問題が残っています。 コンソールの機能を書き換えて、データをインターセプトします。



 function wrapConsole(name, action) { console['$' + name] = console[name];//   console[name] = function () { console['$' + name](...arguments);//   app.sendError( new app.Error(`From console.${name}: ` + [].join.call(arguments, '' ),//      console[name])//     (     v8) .addClueData('console', {//        consoleMethod: name, arg : Array.create(arguments) })[action]());//    }; } wrapConsole('error', 'setTrivial'); wrapConsole('warn', 'setWarning'); wrapConsole('info', 'setWarning');
      
      





2.3サーバー



ここまで読んで疲労で死んでいないすべての人にとって、私たちは最も興味深いものを残しました。 結局、エラーを受け取るドライバーの初期化と実行だけでなく、



すべてのコードはgithub(下のリンク)で表示できます。次に、主なタスクを見てみましょう。



  1. 速度の並列スタート

    これらの目的のために、yield [...](またはPromise.all(...))を使用します。配列の各関数がエラーをスローすべきではないという事実を考慮し、エラーのある関数が複数ある場合、それらすべてを処理することはできません
  2. 柔軟な構成

    すべてのドライバーは「ドライバーパッケージ」に含まれており、優先順位によってアレイに配置されます。 エラーはドライバーパッケージ全体に直ちに送信されます。パッケージ全体が機能しない場合、システムは次のパッケージに進みます。
  3. ダイナミックスタート

    初期化するときに、すべてのドライバーを「開始されていない」としてマークします。

    最初のドライバーパッケージを開始するとき、「開始済み」または「不良」としてマークします。

    現在のパッケージで送信する場合、「bad」をスキップして「started」に送信し、「not started」を実行します。 エラーをスローしたドライバーは不良としてマークされ、先に進みます。 現在のパッケージ内のすべてのドライバーが不良としてマークされている場合は、次のパッケージに進みます。
  4. まだ動作中のドライバーでドライバーエラーを送信する

    エラードライバー自体でエラーが発生した場合(ちょっとしたトートロジー)、特別な配列に書き込みます。 最初のライブドライバーを見つけた後、それを通じてドライバーエラーを送信し、エラー自体(エラー送信時にドライバーがクラッシュした場合)とドライバーエラーを送信します。
  5. フロント/バックエンドでバグをキャッチ

    フロントエンド用の特別なAPIを作成し、process.on( 'uncaughtException'、fn)およびprocess.on( 'unhandledRejection'、fn)を介してnode.js例外をキャッチします


3.結論



説明したエラーメッセージの収集と送信のメカニズムにより、エンドユーザーの前であっても、エラーに即座に対応でき、最後に押されたボタンをエンドユーザーに問い合わせることなく実行できます。



開発について考える場合、将来的にいくつかの便利な機能を追加できます。





実例はgithubで見ることができます。 アーキテクチャについては、oldらないでください。この例は、delete-from-project-all-unnecessaryメソッドを使用して行われました。



コメントさせていただきます。



All Articles