投稿

PostgreSQLとNpgsqlのコネクションプールの挙動

Npgsqlを用いてPostgreSQLと接続したときのコネクションプールの挙動について検証したものをトピック形式でメモしておく。 バージョン ・PostgreSQL 13 ・Npgsql 8.0.1 Npgsqlの接続プールは各プロセス内のメモリで管理される NpgsqlのコネクションプールはNpgsql名前空間内のstaticなクラスで管理されている。プロセスを複数立ち上げればそれぞれ別々にプールされる。 接続プールは接続文字列ごとに管理される 接続プールは接続文字列ごとに管理され同じ接続文字列の場合にのみ再利用される。またプールされる数も接続文字列ごとにカウントされる。 これは仮に接続先が同じでもパラメータが違うだけで別々となる。 接続プール数、保持時間は接続文字列で指定する パラメータ名 意味 未指定時 Pooling プール有無 true MinPoolSize 最小数 1 MaxPoolSize 最大数 100 ConnectionLifeTime 保持時間(秒) 500 接続の再利用時、セッションパラメータはリセットされる プールされた接続は再利用前に次の文を発行して状態をリセットしている。 SET SESSION AUTHORIZATION DEFAULT RESET ALL 不意の停止でサーバ側にセッションが残る場合がある コネクションプールはプロセスの終了時にすべて切断される。ただしプロセスの強制中断などで解放処理が走らないとサーバ側でセッションが残ってしまう。残ったセッションはサーバの同時接続数の枠を埋めてしまう。 接続がプールされた状態でDBを再起動すると次の利用時にエラーになる コネクションプールが残った状態でPostgreSQLサーバを停止・再起動してもプールされた接続のインスタンスは破棄されない。そして次にその接続が再利用されるとNpgsqlException (0x80004005)が発生する。 DBのみ再起動すると予期せぬタイミングで接続エラーとなってしてしまう可能性がある。 最大プール数を超えた場合は待機状態になる MaxPoolSizeを超えてOpenを行ったとき、接続数に空きが出るまで他の処理の終了を待機する。待機する時間は通常の接続タイムアウトと同じで接続文字列(Timeout)で指定できる。 タイム

システム時刻を変更したときの.Netプログラムの時間関係への影響

サーバー系のプログラムでは一定時間ごとに処理を行う定期処理を組む場合がある。もし動作中にOSのシステム時刻を変更された場合にどうなるのか。今回は.NetでのWindowsのシステム時刻を変更したときの動作を確認した。 SleepとDelay まずはSleep系の挙動を確認する。恐らくクロックカウントを利用しているのでシステム時刻の影響は無いと想定される。 Thread.SleepとTask.Delayで次のようなコードを書いた。なお環境は.Net Core3.1だ。 void TestSleep() { while (true) { Thread.Sleep(10000); Debug.WriteLine("tick"); } } async Task TestDelay() { while (true) { await Task.Delay(10000); Debug.WriteLine("tick"); } } プログラムを起動した状態でシステム時刻を適当にずらす。ストップウォッチを持って計測したところ、システム時刻を進めても戻してもきちんと10秒ごとにデバッグ文が出力された。 Thread.SleepとTask.Delayはシステム時刻に影響を受けないことが確認できた。 DateTime.Now 次にDateTimeの現在日時を確認する。Sleepが定期動作することが分かったので次のコードを書く。 void TestDateTime() { while (true) { Thread.Sleep(10000); Debug.WriteLine($"{DateTime.Now:MM/dd HH:mm:ss}"); } } 結果 11/12 21:40:33 11/12 21:40:43 _ここで5秒時間を戻す 11/12 21:40:48 11/12 21:40:58 当然ではあるがシステム時刻に合わせて日時が変わった。このことからDateTime.Nowを経過時間の判定に利用する場合は、時刻飛びや遡りが起きることに注意が必要だ。 Stopwatch 次は高性能

PowerShellスクリプトファイル(ps1)の標準入力へリダイレクトする方法

次のような対話型のPowerShellスクリプトファイルがあったとする。 # hello.ps1 $name = Read-Host your name "Hello $name" | Write-Host Read-Hostで標準入力からユーザの入力を取得している。このスクリプトの呼び出し時に入力を渡して対話を自動化したい。 失敗例 > "Hinata" | .\hello.ps1 your name: スクリプトファイルの呼び出しではパイプラインで文字列を渡しても標準入力にリダイレクトされない。パイプラインの内容は標準入力とは別に$input変数に格納されている。 成功例 > "Hinata" | powershell .\hello.ps1 your name: Hinata Hello Hinata スクリプトの呼び出しではなく、PowerShell実行ファイルにパイプラインで渡して実行させると標準入力にリダイレクトされる。 ただし実行環境が呼び出し元と異なる可能性があることに注意が必要。 > Get-Content .\input.txt | powershell .\hello.ps1 入力元をテキストファイルにする例。改行はEnterキーを押したように処理される。

ClosedXMLで時間値を取得したときの値とEXCELの仕様(特に24時間以上の場合)

イメージ
ClosedXMLで「15:00」のようなセルから、データ値をDateTime型で取得した際の戻り値について。 この記事の内容はClosedXML Ver0.95を対象に書いている。しかしVer0.100で結果が変わったため、誤解の無いように結果のみ先に書いておく。 ・Ver 0.100.0 より前 1899/12/30 HH:mm:ss ・Ver0.100.0 以降 1899/12/31 HH:mm:ss 本文 Excelの時間が入力されたセルから、ClosedXMLで値を取得したとき、TimeSpan型となる場合とDateTime型となる場合がある。これはこれで面倒ではある※が、今回の問題はDateTime型のときだ。 ※ 例えばセルのフォーマットが"[h]:mm:ss"だとTimeSpan型、"[h]:mm"だとDateTime型になったりする Excelでは時刻も日時も内部では同じシリアル値で管理されている。時刻を入力したセルのフォーマットを変更して日付を表示してみると「1900/1/0 ~」と表示される。日付としては不正だが、1日未満という意味で0日なんだろう。 C#のDateTime型では当然0日という日付は表現できない。ではどのような値になるかというと 1899/12/30 ~ そう1899/12/31 ではない のだ。これはExcelの仕様バグに起因する。 1900年2月29日が存在するExcelのバグ 1900年は100の倍数であり400の倍数でないため、本来うるう年ではないのだが、Excelでは仕様バグとして2月29日が存在している。「仕様バグ」と書いたのは、正しくはないが意図的に組み込まれた動作だからだ。 詳しくは以下に公式のアナウンスがある Excel では、1900 年が閏年であると誤って想定されています Windowsが存在する前のソフトとの互換性が、2023年現在でも尾を引いてるというのは面白い。 ちなみにGoogleスプレッドシートでは日時をExcelと同様シリアル値で管理しているが、上記は切り捨てられていて1900年2月29日は存在しない。 ClosedXMLのGetValue ClosedXMLのGetValueでは、DateTime型を生成する際にこの補正などを特にしていないため、1

PowerShellで簡易Webサーバを立てる

PowerShellのバッチでHTTPサーバを立ててみる。今日日開発環境ならば何かしらのデバッグサーバがあるが、それらを用意するほどでもない場合などに用いる。 HTTPサーバを起動する手順 方法としては.NetのSystem.Net.HttpListenerを利用する。 HttpListenerオブジェクトを作成して、任意のポートを開く。 GetContextメソッドでリクエストの受信を待機する。 リクエストの内容に合わせてレスポンスを設定する。 2~3をループで繰り返す。 レスポンスにはファイルを読み込んで返すほか、コマンドを実行した結果を返したりすると簡易リモートサーバ的なこともできる。なおシングルスレッドのためリクエストは一つずつ順番に処理される。 ソースコード 以下はバッチファイルのパスをルートディレクトリとしてファイルデータを返すバッチ。 通信ポートを開くには管理者権限が必要なため、powershellが管理者権限でない場合は管理者に昇格して再起動する処理が最初に入っている。 HttpServer.ps1 $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if(-not $isAdmin){ Start-Process powershell -Verb runAs $MyInvocation.MyCommand.Path exit } $myDir=(Split-path $MyInvocation.MyCommand.Path -parent) $root = "$myDir" $port = "60080" function Listen{ try{ $listener = New-Object System.Net.HttpListener $listener.Prefixes.Add("http://*:$port/") $liste

viewport設定メモおよび「width=device-width, initial-scale=1」とは何か

イメージ
これはmetaタグのviewportの設定に関するメモである。ビューポートの設定は癖があり思い通りにならないので、検証した結果を記載しておく。 モバイルブラウザでのみ有効 ビューポートはモニタの仮想解像度 device-widthはモニタの推奨値 コンテンツがはみ出すとビューポートは広がる initial-scaleの基準はdevice-width initial-scaleがwidthを上回るとビューポートは広がる ビューポートをコントロールしたいとき モバイルブラウザでのみ有効 viewportの設定はスマートフォンなどモバイル版のブラウザでのみ有効となり、PCブラウザでは無視される。 これは長らくドットバイドット表示でウィンドウサイズも可変であったPCに対し、高解像度モニタとズームを用いるスマートフォンでの表示を想定した機能であるため。 ただしこれらは歴史的経緯のためタブレットや2in1PC、および4Kモニタの存在など、今後どうなるかは定かではない。 ビューポートはモニタの仮想解像度 スマートフォンは5インチ幅に1000ピクセル以上などの大きな画素数を持っている。このサイズ感でPCモニタと同じように等倍表示すると、コンテンツが非常に小さく表示されてしまう。 そこで実際の解像度とは別に仮想解像度を設定して、あたかもそのサイズであるかのように調整して描画する。このサイズがビューポートである。 例を挙げると、幅100pxの画像を表示する場合、ビューポートの幅が200であれば画面の1/2、400であれば画面の1/4程度の大きさで表示される。 device-widthはモニタの推奨値 ビューポートがいくらだと見やすいかは画面の物理的なサイズによる。なので機器ごとに「このサイズで表示するといい感じだよ」という値が設定されている。それがdevice-widthである。 webページのユーザビリティ指標でdevice-widthの設定が推奨されるのは、つまりメーカーの想定する使いやすいサイズに合わせろということだ。 コンテンツがはみ出すとビューポートは広がる ビューポートを設定したのにコンテンツが小さく表示されてしまう(ピンチインで縮小できてしまう)場合がある。それはコンテンツサイズがビューポートより大きいからである。 コンテンツの横幅が設定したwidthをはみ出していると、

ソフトウェアにおける日本時間のズレ

日本時間(JST)の時差は世界標準時(UTC)+9時間である。日本は国内時差は無いしサマータイムも採用していないので、それだけ覚えておけば大丈夫。 と思っていたのだが、この度そうでないことを知った。切っ掛けはWindowsのASPで動くバックエンドとChromeブラウザ間でUNIX時刻でやり取りをしていたとき。明治生まれの人の誕生日が微妙にずれる時があるのだ。 日本時間のブレ 調べた結果、日本時間は次の2パターンで+9時間でない場合がある。 1)~1888年 今の日本標準時が設定されたのがこの年(明治21年)だそうだ。ということはこれより前は日本時間自体が存在しないわけだが、システムによっては+9時間18分が採用されている。 2)1949年~1951年の夏 この時期は日本でもサマータイムが導入されていたらしい。なのでこの年の夏季はUNIX時刻も1時間ずれる。 環境による違い 例えばChromeブラウザでJavascriptを動かすと、上記の通りの結果が返ってる。 > new Date(1887, 0, 1, 0, 0, 0) Sat Jan 01 1887 00:00:00 GMT+0918 (日本標準時) > new Date(1950, 7, 1, 0, 0, 0) Tue Aug 01 1950 00:00:00 GMT+1000 (日本標準時) それぞれ+9時間18分、+10時間のタイムゾーンになっている。 今度はWindows PowerShellでやってみる。 > ((Date "1887/1/1") - (Date "1887/1/1" -AsUTC)).ToString() 09:00:00 > ((Date "1950/8/1") - (Date "1950/8/1" -AsUTC)).ToString() 09:00:00 両方ともUTCとの時間差は+9時間となっている。 ChromeブラウザやLinuxなどはタイムゾーンの設定をパブリックなデータベースの「tz database」から取得している。一方でWindowsの場合はMicrosoftが管理する時差データを使っている。Microsoftのデータベースでは上記2ケースの例外は考