【postgreSQL】あれ immediate と思ったら abort してた罠

# データベース落としたくありませんか

業務アプリ開発時にトランザクション制御を手で組みこむ時代は既に古くなったのか
ORマッパーとかに適当にやってもらう「考えなくてよい世界」が過半数なのかしら。

とはいえ標準的なSQLであれば確かに考えなくても作ってくれるので便利ですけれど。
伝票ヘッダに紐づく伝票明細を利用する場合は明細数だけSQLが発行されているとか
普通やらないでしょって。某N+1問題が多発する駄目PGが自動生成される世の中。

ソースレビューだけで簡単に駆逐できないのが嫌。
きっとchatGPTによるコードレビューで救われるようになるに違いない。

## 拝啓。トランザクション貼ったまま落ちないで

先日開発中のプログラムが熱暴走して楽しい光景を見ることができました。

処理の内容はこんな感じ
処理環境；
・ORマッパ；SQLAlchemy (python)
・DBMS；postgreSQL

改修前は単純。

画面で選択した伝票明細テーブルのステータスをキャンセルに変更
与信決済フラグを後続処理で利用するため売上取消に変更するのみ。

ここにきて別システムとの連携が発生したので
別スキーマにある一時テーブルを直接更新する処理が必要になりました。

こんな感じ。

手抜きなので別スキーマの更新も既存のトランザクション処理の中で
別DB接続を追加で実装しています。

```python
# db ・・業務アプリが利用するDB
# con ・・連携用DBとの接続
with ConnectorManager(db_uri).begin() as con:
    with con.session.begin():
        for detail in details:
            if detail.status == 'cancelled':

                detail.autholized_flag = false

                # 連携先からの要望で業務エラー判定を追加
                business_check(detail) # 業務エラーの場合は raise Exception

                con.session.execute(
                    update(table)
                        .where(table.c.slip_number==detail.slip_number)
                        .values(**columns)
                )
                db.session.execute(
                    update(OrderInformation)
                        .where(OrderInformation.slip_number == detail.Slip_number)
                            .values(
                            status = 'canclled'
                    )
                )

        db.session.flush()
    db.session.commit()
```

ちらみすると分かりますが
業務エラー判定でエラーになると連携用DBでトランザクションをはったまま
raise Exception で外側の処理に抜ける実装（駄目

このまま再度データ連携をしようとするとロック待ちのため地球が停止します。
try / catch, finally 重要。

そして。NEXTアクションはDBの再起動。

## postgreSQL を停止する方法

わたくし、出自が Oracle 畑の人なのでDBMSを停止したい場合には
なんとなく以下の３個を打ちたくなります。

```shell
・shutdown
・shutdown immediate
・shutdown abort
```

上から
・全てのクライアントからの接続とトランザクションが終了してから停止。
・全てのクライアントからの接続を強制終了、ロールバックしてから停止。
・全てのクライアントからの接続を強制停止。ロールバックは次回起動時。

今回のケースなら immediate ですよねって。
``pg_ctl stop -m immediate`` 実行。

```python
2023-07-15 22:51:45 JST LOG:  received immediate shutdown request
2023-07-15 22:51:45 JST WARNING:  terminating connection because of crash of another server process
2023-07-15 22:51:45 JST DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
2023-07-15 22:51:45 JST HINT:  In a moment you should be able to reconnect to the database and repeat your command.
```

あれ。一応止まりはしたけど。メッセージが。abnormally？。アブノーマルとは。
なんか最近の流行にのってるのかしら。

あらためて確認したところ postgreSQL って停止パラメタが少し違うこと判明。

:::note info
postgreSQL による停止　[*pg_ctl ガイド参照](https://pgsql-jp.github.io/current/html/app-pg-ctl.html)

”Smart"
全てのクライアントが切断し、オンラインバックアップがあればそれが終了するまで待ちます。 

"Fast"
クライアントが切断するまで待たず、かつ、実行中のオンラインバックアップを終了させます。
 全ての実行中のトランザクションをロールバックし、クライアントとの接続を強制的に切断した後、サーバを停止します。 

"Immediate"
クリーンアップ処理なしで、全てのサーバプロセスを即座に中断します。 
これを指定すると、再起動時にクラッシュリカバリ処理が実行されます。
:::

なんと。
Oracle よりも 1個ずれてませんか。なんで、笑


## まとめ

あらためて 3個のDBMS で停止方法をまとめると

| 停止方法 | postgreSQL | Oracle | MySQL |
|:-:|:-:|:-:|:-:|
| やさしく | smart | normal | - |
| いそいで | fast | immediate | これのみ |
| いますぐ | immediate | abort | - |

ていうか MySQL は選択肢がないw
まあ確かに MS-SQL Server も停止は右クリックしかなかった気も。

MySQL を買収して 10年以上経過するけど
世の中 Oracle が全てではなくなってきた気もする今日この頃。
夏休みの宿題で postgreSQL でも勉強しようかな・・。


## プロセスを落とさないといけない罠（続編

mySQL だと `call mysql.rds_kill(プロセス番号)` なんて落としたりしますが
postgreSQL ってどうするんだろうとか気になってきた

```shell
pg_ctl kill シグナル名 プロセスID
```

シグナル名には Linux の KILLコマンドと同じようなパラメタが。

| シグナル名 | pg_stop -m パラメタ | linux の killコマンド |
|:-:|:-:|:-:|
| term | smart 相当| プロセスの終了命令/15 |
| int | fast 相当| キーボードからの割り込み命令/2 |
| quit | immediate 相当| キーボードからの中止命令/3 |

なんと。
Linux の kill -KILL (シグナル/9) 相当がない。だから分かりにくいったら！

2023/09/26 メモ

postgreSQL のシグナルを調べたところ KILL 相当ありました。
無知の知。恥ずかしい自分に完敗。

:::note info
以下はUNIXシステムで利用可能な主なシグナルの一部です。これらはPostgreSQLやpg_ctlと関連するかどうかは状況によるため、すべてがpg_ctl killコマンドで使用できるわけではありません。

1. `SIGABRT (6)`: プログラムの異常終了を引き起こします。
2. `SIGALRM (14)`: タイマーからのアラートを示します。
3. `SIGBUS (7)`: バスエラー（不正なメモリアクセス）が発生しました。
4. `SIGCHLD (17)`: 子プロセスが停止または終了したことを示します。
5. `SIGCONT (18)`: 停止したプロセスの実行を再開します。
6. `SIGFPE (8)`: 浮動小数点例外が発生しました。
7. `SIGHUP (1)`: ユーザーがターミナルを切り離したことを示します。
8. `SIGILL (4)`: 不正な命令が発生しました。
9. `SIGINT (2)`: インタラクティブな注意シグナルです。
10. `SIGKILL (9)`: 非インタラクティブな注意シグナルです。
11. `SIGPIPE (13)`: パイプが壊れました。
12. `SIGQUIT (3)`: クイットシグナルです。
13. `SIGSEGV (11)`: セグメンテーション違反が発生しました。
14. `SIGSTOP (19)`: 非インタラクティブな停止シグナルです。
15. `SIGTERM (15)`: 終了シグナルです。
16. `SIGTSTP (20)`: インタラクティブな停止シグナルです。
17. `SIGTTIN (21)`: バックグラウンドプロセスが入力を試したことを示します。
18. `SIGTTOU (22)`: バックグラウンドプロセスが出力を試したことを示します。
19. `SIGUSR1 (10)`: ユーザー定義のシグナル1です。
20. `SIGUSR2 (12)`: ユーザー定義のシグナル2です。
21. `SIGPOLL (29)`: ポーラブルオペレーティングシステムインターフェース（POSIX）によって定義された、ポーリング可能なイベ ントが発生したことを示します。
22. `SIGPROF (27)`: CPU時間が経過したことを示します。
23. `SIGSYS (31)`: 不正なシステムコールがありました。
24. `SIGTRAP (5)`: トレーストラップがあることを示します。
25. `SIGURG (23)`: ソケットに緊急データがあることを示します。
26. `SIGVTALRM (26)`: 仮想タイマーは経過しました。
27. `SIGXCPU (24)`: CPUの制限時間を超えました。
28. `SIGXFSZ (25)`: ファイルサイズの制限を超えました。

名前の後の括弧内の数字はシグナルのシステム上での識別子（シグナル番号）です。これらのシグナルは各種のシステム終了や割り込みに使われます。どのシグナルがどのような挙動をするかはシーケンスとオペレーティングシステムによります。

また、これらすべてのシグナルがすべてのシステムで利用可能なわけではなく、具体的なシステムの仕様を確認する必要があります。

pg_ctl killコマンドで利用するにあたっては、それぞれのシグナルがPostgreSQLのプロセスにどのような影響を与えるか、またその 影響が望ましいものかを十分理解した上で使用することが重要です。:::
:::
さすがchatGPT先生ｗ