2025年6月の振り返り
ブログをサボって早1年経過しようとしていた。
お仕事
ブログをサボりだしたときにプロジェクトが変わって、夜が遅くなって朝活が厳しくなり...
まー。言い訳です。
途中で、育成兼ねてプロジェクトリーダーになりました。リーダー業務を全て巻き取ってないけど、色々言われてすでに気が滅入っている。
リーダーになる前からちょこちょこ言ってたが、周りに響かず、負債を抱えた状態でリーダーになってしまった。
全部を巻き取らないといけないが、果たして私にリーダーが出来るのか....
日々、不安でしかない。
リーダーになってみて思うこと
リストと課題をいかに抽出して管理していくかというのは改めて重要と感じた。
そして、プロジェクトメンバーから全く課題やリストが出てこないのは正常なプロジェクトではないと考える。
メンバーが作業をやり始めて、これが足りないとかその状況にならないと出てこないのは一人一人がゴールに目を向けてないからじゃないかなと思う。
そう考えると、プロジェクトリーダーになる前は、めちゃくちゃ課題あげたり、リスクあげたりしてたな...
スケジュールに余裕があったのもあるが、全然休出とかなく過ごせていたので、課題やリスク管理は大事だ。
優しさ < 厳しさ
周りのリーダーは優しいみたいだけど、自分は優しくできない。
なんで、作業遅れの責任を自分が持たないといけないのか?
成果物の責任はリーダーが持つ必要があるが、成果物の責任は作業者にあるわけだから、責任はきちんと持ってもらいたい。
だから、私は優しいプロジェクトリーダーにはなれない。
最後に
ブログは月1回は投稿しようと思う。
最近、リーダーの本を読んでこれはよかった。
次はこれらを読みたい。
2024年9月の振り返り
プロジェクトの方は何とも言えない感じ。
声に出して楽しいと言えるようなプロジェクトではないが、自分が知らなかったこと、新しいことに出会えているので
その瞬間は不安や焦りが出てしまうが、なんとか学びながら進みたい。
とりあえず、今のところは順調なはず。
朝活または夜活を20分やる
9月もやり切った。 BINDをやってみたり、Pythonのroadmapを使って、基礎を見直してみた。 新しい気づきもあったが、記事に出来なかったのは残念。 今は、AWS ASSの取得のために時間を使っている。
ブログはお休み
9月は、3187PVだった。
朝活または夜活の時間をAWS ASSの資格取得に向けて時間を使うことにした。
これもあれもとなると、どっちつかずになってしまうので、資格を取ることを優先するためにブログは一旦お休みする。
資格の勉強
ちょっとしたきっかけがあったので、朝活または夜活とブログを書く時間を利用して、勉強中。
資格勉強自体が苦手なので、受かることができるかどうか不安でいっぱい。
人よりも時間がかかってしまうし、暗記力もないので、不安だらけ。
とりあえず、10月末には合格していたい。
最近、思うこと
HIITをやり始めたが、出社した日は遅く帰ってきて、すぐに夕飯を食べないと怒られるので、
食後にHIITをするとめっちゃきついのね。
だから、出来て週一しか出来てなかった。
テレワークの日は朝に走ったら、そこでHIITを始めたおかげか思いのほか走れて、ちょっと嬉しかった。
そして、資格取得に向けて勉強時間を確保するために、朝5時から5時半の間に起床して勉強してたんだが、一昨日発熱。
睡眠時間が確実に減っていたのは、わかってたけど、こんなに早く体調を崩すとは、つくづく自分の身体の弱さがなさけなくなる。どうやったら、風邪をひかずに一年過ごせずのか知りたい。
というわけで、病み上がりなので、HIITとかランニングは1週間ほどサボり期間で、また来週から頑張ろう。
ExceptionGroupでExceptionをまとめる

改めて、Pythonの基本の見直そうとroadmapをベースに記事を読んだり、マニュアルを読んだりしている。
その時に、ExceptionGroupの存在を知った。
ExceptionGroupは、バージョン3.11で追加されている。
何をするためのものか?
マニュアルと見ると以下のように書かれている。
最初の例外を送出するよりも、処理を継続して複数の例外を集約した方が望ましいユースケースもある。 組み込みのExceptionGroupは例外インスタンスのリストをまとめ、同時に送出できるようにする。 ExceptionGroupも例外なので、他の例外と同じように捕捉できる。
複数の宛先に非同期で通信した際に、例外が発生してもそのまま処理して、最後に呼び出し元に例外を送出するような場合が1つあると思う。
どうやって使うのか?
ExceptionGroupは、例外を配列でまとめたものを渡してインスタンスを生成する。 以下の場合は、OSErrorとSystemErrorを配列に入れている。
excs = [OSError("error 1"), SystemError("error 2")] raise ExceptionGroup("there were problems", excs)
例外を捕捉する側は、通常はexceptを使用するが、ExceptionGroupに含まれる例外に対して処理をしたい場合は、 except*を使用する。
以下の場合、ExceptionGroupに含まれるOSErrorとSystemErrorがそれぞれの節で処理される。
def f(): excs = [OSError("error 1"), SystemError("error 2")] raise ExceptionGroup("there were problems", excs) try: try: f() except* OSError as e: print("There were OSErrors") except* SystemError as e: print("There were SystemErrors") except Exception as e: print(f"raiseされたよ {type(e)}")
except*節で例外を送出したらどうなる?
expcet*内で例外を送出すると上位側にはOSErrorとSystemErrorが含まれたExceptionGroupが送出される。そのため、個々の例外がそう送出されることはない。
def f(): excs = [OSError("error 1"), SystemError("error 2")] raise ExceptionGroup("there were problems", excs) try: try: f() except* OSError as e: print("There were OSErrors") raise Exception("OSErrosだよ") except* SystemError as e: print("There were SystemErrors") raise Exception("SystemErrorsだよ") except Exception as e: print(f"raiseされたよ {type(e)}")
最後に
ExceptionGroupというものがあることを全く知らなかったのでよい勉強になった。引き続き、roadmapを参考に基礎部分を復習してPythonの理解を深めようと思う。
参考
SQLAlchemyでのJoinで結合したデータを取得

前回、SELECT 〜 JOIN をやってみたが、期待通りのことが出来なかった。 少し調べたら、やり方がわかったのでまとめておく。
selectメソッドに対象のモデルを指定する
selectメソッドで検索時に取得するデータのモデルを指定して、executeメソッドを実行するだけ。
scalarsメソッドは特定のカラムの値を抽出するために使用するため、scalarsメソッドでデータ取得するとStudentテーブルのデータが取得できない。
executeメソッドは、全体の結果を取得するため、結合して取得したデータに対して、対応するモデルに値を設定してくれる。
stmt = select(School, Student).join(School, Student.school_id == School.id) results = session.execute(stmt)
値の参照方法
以下のように、Rowインスタンスにモデルクラス.変数名でアクセスできる。
Studentテーブルのnameカラムの値を取得したい場合、Rowインスタンスの変数名.Student.nameで取得する。
print("student.id = " + str(result.Student.id)) print("student.name = " + str(result.Student.name)) print("student.school.name = " + str(result.School.name))
最後に
SQLAlchemyのマニュアルに複数のORMエンティティを使用する場合について記載されていた。やりたいことがマニュアルに書かれていたので、改めてマニュアルを確認することは大事だと気付かされた。
参考
ソース
from sqlalchemy import create_engine from sqlalchemy.types import Integer, String from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import relationship from sqlalchemy import ForeignKey from sqlalchemy import select class Base(DeclarativeBase): pass class Student(Base): __tablename__ = "student" id: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(30)) school_id: Mapped[int] = mapped_column(ForeignKey("school.id")) class School(Base): __tablename__ = "school" id: Mapped[int] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(String(30)) # DBエンジンを作成 url = "postgresql://postgres:example@localhost:5432/postgres" engine = create_engine(url, echo=True) # テーブルをDBに作成 Base.metadata.create_all(engine) # セッションを作成 # セッションを介してクエリを実行する SessionClass = sessionmaker(engine) session = SessionClass() school1 = School(name="あいうえお学園") school2 = School(name="かきくけこ学園") school3 = School(name="さしすせそ学校") session.add_all([school1, school2, school3]) session.commit() student1 = Student(name="sato", school_id=1) student2 = Student(name="tanaka", school_id=2) student3 = Student(name="watanabe", school_id=3) session.add_all([student1, student2, student3]) session.commit() stmt = select(School, Student).join(School, Student.school_id == School.id) # results = session.scalars(stmt) results = session.execute(stmt) for result in results: print("student.id = " + str(result.Student.id)) print("student.name = " + str(result.Student.name)) print("student.school.name = " + str(result.School.name))
version: "3.1" services: db: image: postgres restart: always environment: POSTGRES_PASSWORD: example ports: - 5432:5432 adminer: image: adminer restart: always ports: - 8080:8080
2024年8月の振り返り

8月から徐々に新しいプロジェクトの作業が始まった。 夏季休暇前は気持ちがのってなかったが、休み明けは気持ちを切り替えて作業が出来ているように 思える。 だが、リーダーの立ち位置ではないので、今後リーダーとなりマネージャになれるのか不安もある。 今は、今できることを全力でやろう。 新しいプロジェクトでは、「楽しむ」ということを目標にする。 きっと、進捗が遅れて、上位上司に怒鳴られる場面が出てくるはず。(現実になるかはわからん) そんな時でも、マイナスにならず、周りに声をかけて「楽しむ」というのを意識したい。 この「楽しむ」ということが出来れば、リーダーとしてもやっていけるんじゃないかなと。 自分のマインドは常にマイナスなので、マインドを変えるチャンスにもなるはずだ。
朝活または夜活を20分やる
夏季休暇もあったが、帰省先にもMacBookを持ち帰って実施出来た。 2021年に5か月しか継続して出来なかったことが8か月続けられている。 残り4か月を何とかやり切りたい。 きっと、1年通してやれれば、自信にも繋がるはずだ。
先月のPV数を更新
8月も週1ペースを維持できた。 1日のPV数も初めて200PVを超えることができた。また、8月は、3461PVだった。 9月も週1ペースは維持していきたい。
資格の勉強
腹を括れていない。どうしましょうという感じ。
最近、思うこと
最近、思うことと言うか、夏季休暇明けたら体重が3キロぐらい増加していた。 Tシャツを着て、鏡を見るとお腹が出ているように見える。さすがにやばいなと思ったのと習慣化するアプリを 試していることもあり、HIITを始めた。 学生時代は、めちゃくちゃ動き回っていたが、就職してデスクワークになり、学生時代の反動でかきつい運動はしたくなくなった。 その結果、HIITやり始めたら、めちゃくちゃきつい。 高強度トレーニングなので、きついのは当たり前なのだが。始めたけど、全く痩せずで... 習慣化と合わせて、継続できるようにしたい。 問題は、出社したときにいつやるか。朝するのか?帰宅してするのか?
DRBDによるリアルタイムミラーリング

モチベーション
HA環境を構築する際に、プロジェクトでrsyncを使ってファイルの同期をしていた。 ただ、pacemakerで検索するとDRBDを組み合わせて使う記事がいくつか見られたので、DRBDを試してみて、どういったものなのかの概要を掴む。
DRBDとは
DRBD(Distributed Replicated Block Device)とは、TCP/IPネットワークを通じて複数のサーバのストレージ(パーティション)をリアルタイムにミラーリング(複製)するソフトウェア。 RAID1のようなミラーディスクを構築が可能。 RAIDは、同じサーバ内のストレージを冗長化するが、DRBDは複数のサーバーのストレージを使用する。
https://bcblog.sios.jp/brbd-index/
DRBDとPacemakerを組み合わせると簡単かつ安全はハイアベイラビリティクラスタ環境(HAクラスタ環境)が構築可能。
環境
VagrantでRocky linux 9のVMを起動。
それぞれのVMにディスク(/dev/sdb)を追加しておく
前準備
Vagrantで構築するVMには、ディスクが1枚(/dev/sda)しかないので、/dev/sdbを追加しておく。
/dev/sdbを追加して、VMを起動したら、パーティションを作成しておく。
また、DRBDの定義でホスト名を使用するため、/etc/hostsにも定義を追加しておく。
検証環境のfirewallは停止したままとする。firewallを起動しておく場合は、7788-7799のポート番号の
ポートの解放が必要になる。
firewall-cmd --permanent --add-port=7788-7799/tcp firewall-cmd --reload
パーティションテーブルの作成
parted -s -a optimal /dev/sdb mklabel gpt
パーティションの作成
parted -s -a optimal /dev/sdb -- mkpart primary xfs 1 -1
hostsファイルの編集
vi /etc/hostsで下記の定義を追加する。
192.168.56.10 server1 192.168.56.11 server2
インストール
drbdとkmod-drbdをインストール(server1/server2の両方で実行)
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org dnf install -y https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm dnf install -y drbd9x-utils kmod-drbd9x
ファイルの同期のための定義ファイルを作成する(server1/server2の両方で実行)
vi /etc/drbd.d/drbd0.res
resource drbd0 {
protocol C;
disk /dev/sdb1;
device /dev/drbd0;
meta-disk internal;
on server1 {
address 192.168.56.10:7789;
}
on server2 {
address 192.168.56.11:7789;
}
}
メタデータの作成(server1/server2の両方で実行)
drbdadm create-md drbd0
下記のメッセージが出力される。
initializing activity log initializing bitmap (320 KB) to all zero Writing meta data... New drbd meta data block successfully created.
リソースの有効化(server1/server2の両方で実行)
drbdadm up drbd0
実行すると以下のようなメッセージが出力される。
--== Thank you for participating in the global usage survey ==-- The server's response is: you are the 2106th user to install this version
状態の確認(server1/server2の両方で実行)
drbdadm statusを実行する。
drbd0 role:Secondary
disk:Inconsistent
server2 role:Secondary
peer-disk:Inconsistent
diskがInconsistentになっているので、不一致の状態。
データ同期
server1をprimaryにするので、server1で実行する。
drbdadm primary --force drbd0
状態の確認
状態を確認するために、drbdadm status <リソース>を実行する。
drbdadm status drbd0
出力結果は以下のような出力になる。
drbd0 role:Primary
disk:UpToDate
server2 role:Secondary
replication:SyncSource peer-disk:Inconsistent done:0.72
出力内容を確認すると以下のようになる。
| 出力 | 内容 |
|---|---|
| drbd0 role:Primary | コマンドを実行したサーバのroleを出力。server1はPrimary |
| disk:UpToDate | DRBDで管理しているストレージの状態を表す |
| server2 role:Secondary | 同期先のサーバのroleを出力。 |
| replication:SyncSource peer-disk:Inconsistent done:0.72 | 同期状態を表す。同期中なのでdoneの値がコマンドを実行するたびに増加する |
同期が完了すると以下のように、UpToDateの状態になる。
drbd0 role:Primary
disk:UpToDate
server2 role:Secondary
peer-disk:UpToDate
動作確認
server1がprimaryなので、server1で作業を実施する。
mkfs.xfs /dev/drbd0
# 出力結果
meta-data=/dev/drbd0 isize=512 agcount=4, agsize=655274 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=1, rmapbt=0
= reflink=1 bigtime=1 inobtcount=1 nrext64=0
data = bsize=4096 blocks=2621095, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0, ftype=1
log =internal log bsize=4096 blocks=16384, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
/dev/drbd0にファイルシステムを作成して、マウントする。
その後に、ファイルを作成して、アンマウントする。
mount /dev/drbd0 /mnt echo "test" > /mnt/backup.txt cat /mnt/backup.txt test umount /mnt
server2で/dev/drbd0にマウントし、ステータスを確認する。
mount /dev/drbd0 /mnt drbdadm status drbd0
mountすると自動的にPrimaryに昇格され、 umountすると自動的にSecondaryに降格される。これは、DRBD9では自動プロモーションが有効になっているため。 server1でステータスを確認すると、Secondaryになっていた。
drbd0 role:Primary
disk:UpToDate
server1 role:Secondary
peer-disk:UpToDate
server1で作成したファイルの内容を出力する。
cat /mnt/backup.txt
以下のメッセージが出力され、ファイルが同期されていることがわかる。
test
再起動したらステータスが見えない
サーバーを再起動すると、ステータスが見えなくなった。 原因は、DRBDのサービスが停止していたため。 DRBDをインストールした際に、サービスの自動起動設定はされないので、手動で設定する必要がある。
server1/server2でサービスを自動起動するように設定し、再起動。
systemctl enable drbd systemctl reboot
サーバー再起動後に、drbdadm status allを実行して結果が取得できた。
drbd0 role:Secondary
disk:UpToDate
server2 role:Secondary
peer-disk:UpToDate
最後に
ファイルはrsyncを使って同期をするものかと思っていたが、ブロックデバイスを同期するDRBDの存在を知ることが出来てよかった。 pacemaker+DRBDというは検索すると情報がそこそこあるが、プロジェクトで使っているところは聞いたことがないので、今後プロジェクトで使えるか検討してみたい。 mountすると自動でPrimaryに昇格するが、どのような設定をしたらPrimaryだけmountするのかがわからないので、pacemaker+DRBDをやる際に確認する。
参考
Vagrantで追加ディスクを追加する方法
VMにディスクが複数必要になったので、設定方法を調べて試した。
以下のdiskの定義を追加すればよい。
自分の環境だと、追加のディスクは/dev/sdbに追加された。
config.vm.disk :disk, size: "10GB", name: "extra_storage"
fdisk -lを実行して、/dev/sdbが追加されたことを確認できる。
# fdisk -l Disk /dev/sdb: 10 GiB, 10737418240 bytes, 20971520 sectors Disk model: VBOX HARDDISK Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk /dev/sda: 10 GiB, 10737418240 bytes, 20971520 sectors Disk model: VBOX HARDDISK Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: gpt Disk identifier: 31708F37-29EF-4E85-BE83-713DF6452BB1 Device Start End Sectors Size Type /dev/sda1 2048 206847 204800 100M EFI System /dev/sda2 206848 2254847 2048000 1000M Linux filesystem /dev/sda3 2254848 2263039 8192 4M PowerPC PReP boot /dev/sda4 2263040 2265087 2048 1M BIOS boot /dev/sda5 2265088 18649087 16384000 7.8G Linux filesystem


