error handle #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: RPC Healthcheck | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| on: | |
| schedule: | |
| - cron: '41 2 * * *' | |
| - cron: '41 10 * * *' | |
| - cron: '41 18 * * *' | |
| workflow_dispatch: | |
| # debug | |
| push: | |
| branches: | |
| - dl-rpc-check | |
| jobs: | |
| check-networkinfo: | |
| name: Check ${{ matrix.network }} networkInfo | |
| if: ${{ github.repository == 'QuarkChain/goquarkchain' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - network: mainnet | |
| rpc_url: https://rpc.indexer.mainnet.quarkchain.io:38391 | |
| expected_network_id: "0x1" | |
| - network: devnet | |
| rpc_url: https://rpc.indexer.devnet.quarkchain.io:38392 | |
| expected_network_id: "0xff" | |
| - network: mainnetHost | |
| rpc_url: http://65.108.121.223:38391 | |
| expected_network_id: "0x1" | |
| - network: devnetHost | |
| rpc_url: http://50.112.62.65:38391 | |
| expected_network_id: "0xff" | |
| steps: | |
| - name: Check endpoint JSON field | |
| shell: bash | |
| env: | |
| RPC_URL: ${{ matrix.rpc_url }} | |
| EXPECTED_NETWORK_ID: ${{ matrix.expected_network_id }} | |
| NETWORK_NAME: ${{ matrix.network }} | |
| run: | | |
| set -euo pipefail | |
| payload='{"jsonrpc":"2.0","id":"id","method":"networkInfo","params":[]}' | |
| resp_file="${RUNNER_TEMP}/networkinfo_${NETWORK_NAME}.json" | |
| report_file="${RUNNER_TEMP}/networkinfo_report_${NETWORK_NAME}.json" | |
| : > "$resp_file" | |
| code="$( | |
| curl --silent --show-error --location \ | |
| --retry 3 --retry-delay 5 --retry-all-errors \ | |
| --connect-timeout 10 --max-time 30 \ | |
| -X POST \ | |
| -H 'Content-Type: application/json' \ | |
| --data "$payload" \ | |
| --output "$resp_file" --write-out '%{http_code}' \ | |
| "$RPC_URL" \ | |
| || echo '000' | |
| )" | |
| result="success" | |
| error_msg="" | |
| if [[ "$code" != "200" ]]; then | |
| result="failure" | |
| error_msg="HTTP status not 200: $code" | |
| elif ! jq -e --arg expected "$EXPECTED_NETWORK_ID" '.result.networkId == $expected' "$resp_file" > /dev/null; then | |
| result="failure" | |
| error_msg="JSON check failed: .result.networkId == $EXPECTED_NETWORK_ID" | |
| fi | |
| jq -n \ | |
| --arg network "$NETWORK_NAME" \ | |
| --arg rpc_url "$RPC_URL" \ | |
| --arg result "$result" \ | |
| --arg error "$error_msg" \ | |
| '{network: $network, rpc_url: $rpc_url, result: $result, error: $error}' > "$report_file" | |
| if [[ "$result" != "success" ]]; then | |
| echo "[$NETWORK_NAME] $error_msg" | |
| cat "$resp_file" | |
| exit 1 | |
| fi | |
| echo "[$NETWORK_NAME] JSON check passed: .result.networkId == $EXPECTED_NETWORK_ID" | |
| - name: Upload endpoint report | |
| if: ${{ always() }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: rpc-healthcheck-${{ matrix.network }} | |
| path: ${{ runner.temp }}/networkinfo_report_${{ matrix.network }}.json | |
| if-no-files-found: error | |
| notify: | |
| name: Notify (email) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| needs: | |
| - check-networkinfo | |
| if: ${{ always() && github.repository == 'QuarkChain/goquarkchain' }} | |
| steps: | |
| - name: Download endpoint reports | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: rpc-healthcheck-* | |
| merge-multiple: true | |
| path: ${{ runner.temp }}/rpc-healthcheck | |
| - name: Compose email | |
| id: compose | |
| shell: bash | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| EVENT_SCHEDULE: ${{ github.event.schedule }} | |
| CHECK_RESULT: ${{ needs.check-networkinfo.result }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| run: | | |
| set -euo pipefail | |
| send=false | |
| overall="OK" | |
| report_dir="${RUNNER_TEMP}/rpc-healthcheck" | |
| table_rows_with_error='' | |
| table_rows_no_error='' | |
| html_rows_with_error='' | |
| html_rows_no_error='' | |
| shopt -s nullglob | |
| report_files=("$report_dir"/*.json) | |
| if [[ ${#report_files[@]} -eq 0 ]]; then | |
| overall="FAILED" | |
| send=true | |
| table_rows_with_error='| unknown | unknown | failure | missing endpoint report artifact |' | |
| html_rows_with_error='<tr><td>unknown</td><td>unknown</td><td>failure</td><td>missing endpoint report artifact</td></tr>' | |
| else | |
| for f in "${report_files[@]}"; do | |
| network="$(jq -r '.network' "$f")" | |
| rpc_url="$(jq -r '.rpc_url' "$f")" | |
| result="$(jq -r '.result' "$f")" | |
| error="$(jq -r '.error' "$f")" | |
| if [[ "$result" != "success" ]]; then | |
| overall="FAILED" | |
| send=true | |
| if [[ -z "$error" ]]; then | |
| error="unknown error" | |
| fi | |
| else | |
| if [[ -z "$error" ]]; then | |
| error="-" | |
| fi | |
| fi | |
| # Escape markdown table special chars | |
| rpc_url="${rpc_url//|/\\|}" | |
| error="${error//|/\\|}" | |
| table_rows_with_error+="| ${network} | ${rpc_url} | ${result} | ${error} |\n" | |
| table_rows_no_error+="| ${network} | ${rpc_url} | ${result} |\n" | |
| network_html="${network//&/&}" | |
| network_html="${network_html//</<}" | |
| network_html="${network_html//>/>}" | |
| rpc_url_html="${rpc_url//&/&}" | |
| rpc_url_html="${rpc_url_html//</<}" | |
| rpc_url_html="${rpc_url_html//>/>}" | |
| result_html="${result//&/&}" | |
| result_html="${result_html//</<}" | |
| result_html="${result_html//>/>}" | |
| error_html="${error//&/&}" | |
| error_html="${error_html//</<}" | |
| error_html="${error_html//>/>}" | |
| html_rows_with_error+="<tr><td>${network_html}</td><td>${rpc_url_html}</td><td>${result_html}</td><td>${error_html}</td></tr>" | |
| html_rows_no_error+="<tr><td>${network_html}</td><td>${rpc_url_html}</td><td>${result_html}</td></tr>" | |
| done | |
| fi | |
| if [[ "$CHECK_RESULT" != "success" ]]; then | |
| overall="FAILED" | |
| send=true | |
| else | |
| # Success: send only on manual trigger, or once per day for scheduled runs. | |
| if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then | |
| send=true | |
| elif [[ "$EVENT_NAME" == "schedule" ]]; then | |
| if [[ "${EVENT_SCHEDULE:-}" == "41 18 * * *" ]]; then | |
| send=true | |
| fi | |
| fi | |
| fi | |
| if [[ "$overall" == "OK" ]]; then | |
| subject="✅ QuarkChain RPC Healthcheck OK" | |
| else | |
| subject="❌ QuarkChain RPC Healthcheck FAILED" | |
| fi | |
| # debug | |
| send=true | |
| echo "send=$send" >> "$GITHUB_OUTPUT" | |
| echo "subject=$subject" >> "$GITHUB_OUTPUT" | |
| echo "body<<EOF" >> "$GITHUB_OUTPUT" | |
| echo "QuarkChain RPC Healthcheck: $overall" >> "$GITHUB_OUTPUT" | |
| echo >> "$GITHUB_OUTPUT" | |
| echo "Event: $EVENT_NAME" >> "$GITHUB_OUTPUT" | |
| echo "Schedule: ${EVENT_SCHEDULE:-N/A}" >> "$GITHUB_OUTPUT" | |
| echo "Run: $RUN_URL" >> "$GITHUB_OUTPUT" | |
| echo >> "$GITHUB_OUTPUT" | |
| if [[ "$overall" == "OK" ]]; then | |
| echo "| network | rpc_url | result |" >> "$GITHUB_OUTPUT" | |
| echo "|---|---|---|" >> "$GITHUB_OUTPUT" | |
| printf "%b" "$table_rows_no_error" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "| network | rpc_url | result | error |" >> "$GITHUB_OUTPUT" | |
| echo "|---|---|---|---|" >> "$GITHUB_OUTPUT" | |
| printf "%b" "$table_rows_with_error" >> "$GITHUB_OUTPUT" | |
| fi | |
| echo "EOF" >> "$GITHUB_OUTPUT" | |
| echo "html_body<<EOF" >> "$GITHUB_OUTPUT" | |
| echo "<p>QuarkChain RPC Healthcheck: <b>${overall}</b></p>" >> "$GITHUB_OUTPUT" | |
| echo "<p>Event: ${EVENT_NAME}<br/>Schedule: ${EVENT_SCHEDULE:-N/A}<br/>Run: <a href=\"${RUN_URL}\">${RUN_URL}</a></p>" >> "$GITHUB_OUTPUT" | |
| echo "<table border=\"1\" cellpadding=\"6\" cellspacing=\"0\" style=\"border-collapse: collapse;\">" >> "$GITHUB_OUTPUT" | |
| if [[ "$overall" == "OK" ]]; then | |
| echo "<thead><tr><th>network</th><th>rpc_url</th><th>result</th></tr></thead>" >> "$GITHUB_OUTPUT" | |
| echo "<tbody>${html_rows_no_error}</tbody>" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "<thead><tr><th>network</th><th>rpc_url</th><th>result</th><th>error</th></tr></thead>" >> "$GITHUB_OUTPUT" | |
| echo "<tbody>${html_rows_with_error}</tbody>" >> "$GITHUB_OUTPUT" | |
| fi | |
| echo "</table>" >> "$GITHUB_OUTPUT" | |
| echo "EOF" >> "$GITHUB_OUTPUT" | |
| - name: Send email | |
| if: ${{ steps.compose.outputs.send == 'true' }} | |
| uses: dawidd6/action-send-mail@v6 | |
| with: | |
| server_address: smtp.gmail.com | |
| server_port: 465 | |
| username: ${{ secrets.RPC_HEALTHCHECK_SMTP_USERNAME }} | |
| password: ${{ secrets.RPC_HEALTHCHECK_SMTP_PASSWORD }} | |
| from: QuarkChainRPC | |
| to: ${{ secrets.RPC_HEALTHCHECK_EMAIL_TO }} | |
| subject: ${{ steps.compose.outputs.subject }} | |
| body: ${{ steps.compose.outputs.body }} | |
| html_body: ${{ steps.compose.outputs.html_body }} |