Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
PHPer's Guide to Daemon Crafting Taming and Sum...
Search
uzulla
March 22, 2025
Programming
2
1.8k
PHPer's Guide to Daemon Crafting Taming and Summoning
at: PHPerKaigi 2025
date: 2025/03/22
speaker: uzulla
uzulla
March 22, 2025
Tweet
Share
More Decks by uzulla
See All by uzulla
ALL CODE BASE ARE BELONG TO STUDY
uzulla
30
7.2k
バイブスあるコーディングで ~PHP~ 便利ツールをつくるプラクティス
uzulla
1
480
似たもの同士のPerlとPHP
uzulla
1
270
More Context, Better Code. 既存コードやOAS等をコンテキストとしてLLMに与える事で、よりよいコード生成を行う話
uzulla
1
190
あなたのアプリ、ログはでてますか?あるいはログをだしてますか? (Funabashi.dev用 軽量版)
uzulla
3
290
セッションのトークセッション / Traps for PHP session features in growing web apps
uzulla
2
220
Crafting a Own PHP - ウキウキ手作りミニマリストPHP
uzulla
5
2.8k
例外を投げるのをやめてみないか? あるいは受け入れてみないか? - How to use exceptions other than throwing
uzulla
6
1.3k
PHPerが ISUCONでやるべき事
uzulla
1
1.5k
Other Decks in Programming
See All in Programming
Developing static sites with Ruby
okuramasafumi
0
200
30分でDoctrineの仕組みと使い方を完全にマスターする / phpconkagawa 2025 Doctrine
ttskch
3
790
宅宅自以為的浪漫:跟 AI 一起為自己辦的研討會寫一個售票系統
eddie
0
490
Cap'n Webについて
yusukebe
0
110
堅牢なフロントエンドテスト基盤を構築するために行った取り組み
shogo4131
8
2.2k
AIエージェントを活かすPM術 AI駆動開発の現場から
gyuta
0
340
AIエンジニアリングのご紹介 / Introduction to AI Engineering
rkaga
5
1.9k
新卒エンジニアのプルリクエスト with AI駆動
fukunaga2025
0
190
エディターってAIで操作できるんだぜ
kis9a
0
690
リリース時」テストから「デイリー実行」へ!開発マネージャが取り組んだ、レガシー自動テストのモダン化戦略
goataka
0
120
バックエンドエンジニアによる Amebaブログ K8s 基盤への CronJobの導入・運用経験
sunabig
0
140
AIコードレビューがチームの"文脈"を 読めるようになるまで
marutaku
0
340
Featured
See All Featured
VelocityConf: Rendering Performance Case Studies
addyosmani
333
24k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
51k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
54k
Making Projects Easy
brettharned
120
6.5k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
1.8k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Large-scale JavaScript Application Architecture
addyosmani
514
110k
BBQ
matthewcrist
89
9.9k
Done Done
chrislema
186
16k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
We Have a Design System, Now What?
morganepeng
54
7.9k
Producing Creativity
orderedlist
PRO
348
40k
Transcript
PHPer's Guide to Daemon Crafting, Taming and Summoning
Re:લઆ
ݩؾͰ͔͢ʂ
ݩؾ͋ΕͳΜͰͰ͖Δʂ
͕ʂ PHPͱ͍͑ ApacheNginx͕͍ͳ͍ͱ͏͔͝ͳ͍ ಠΓཱͪͰ͖ͳ͍ݴޠ (ॾઆ͋Δ)
ࢲʮॻ͚ΔΖ(աڈͷτʔΫࢀর)ʯ ʁʮPHPͰhttpdΛॻ͘ is ͦ͠͏ʯ ࢲʮී௨ʹΕΑ͍(աڈͷτʔΫࢀর)ʯ ʁʮͦ͏͍͏ͱ͜ΖͰ͢Αʁʁʁʁʯ
! GoogleʮPHPͰσʔϞϯʁΒͳ͍ʂʯ ! CopolotʮαϙʔτͳΜͰ…ʯ ! ChatGPTʮ͍ͷແཧͰ͢ʯ
…ͦΜͳઈͷ͕࣌ଓ͖·ͨ͠ ʢԶҎ֎ͦ͏Ͱͳ͍͔ʁʁʁʁʣ
͔͠͠ʂ2025ʂʂʂʂ ͍ͭʹٹੈओ͕ݱΕͨʂʂ
Devin/Claude code:ɹɹ ʮ͑ɺ͓લPHPͰσʔϞϯॻ͚ͳ͍ͷʁ ॻ͍ͯΔΑʯ
͍ͭʹʮͳʹ͔Θ͔ΒΜ࣌ʯ͕ऴΘͬͨ… ʢ͍ɺਓؒͳʹ͔Θ͔͓ͬͯΒΜ͕ɺಈ࡞͢Δαϯϓϧ͕ݟΕΔʂʣ
Ͱɺͩɻ
ࠓճࢲAIʹίʔυΛॻ͔͍ͤͯ·͕͢ Θ͟ͱͰ͢
ෛ͚੯͠ΈͰͳ͘ʂʂʂ ࢲ͕ࣗθϩ͔ΒίʔυΛॻ͚ͳ͍Θ͚Ͱͳ͍ʂʂ(ͬͯ͠ΔͩΖʂ) ෛ͚੯͠ΈͰͳ͘ʂʂʂ Θ͟ͱͰ͢ʂʂʂʂʂʂ
օ͞Μ͕खʹೖΕΒΕΔͱ͍͏ࣄ͕ॏཁͳͷͰ͢ʂ
ʁʮPHPͰσʔϞϯʁ͍Έ͋Δͷʁʯ ࢲʮϩϚϯ͕͋Γ·͢ʂʂʂʂʂʂʯ
ҰൠతͳΠϝʔδ
ApacheNginxඞཁ͕ͳ͍ PHP γϯάϧϓϩηε୯ମͰಈ͘ϓϩάϥϜ ڵຯ͕͋Γ·ͤΜ͔ʂʁ(Զ͚͔ͩʁ)
ࠓճλΠτϧੌͭ͘·Βͳͦ͏͡Όͳ͍Ͱ͔͢ʂʂʂ Ͱ͍ͭʹγάφϧॲཧsystemdͷཱ͕ͭΜͰ͢ʂʂʂ
ʮѱ͍ͳɺσʔϞϯ࡞PHPʹແཧͳΜͩʯ ͏͍ΘͤͶ͑ͧʂʂʂ
CMS࡞ݴޠͱ͔͍ΘΕ͍ͯͨ PHPͷ͠Ϳͱ͞Λ ͋ΒͨΊͯΈͤͯΓ·͢Αʂʂʂ
ؓٳ
ʮԶ͕PHPerKaigiͩʂ(???)ʯ ‣ ͱɺݴ͑Δఔʹ(ʁ) ॳճ͔Βຖొஃ(લࡇؚΉ) ‣ ओʹPHPܥόοΫΤϯυΤϯδχΞ ‣ ʮઓʹಥવ͛ࠐ·ΕΔ༭ฌΛͯ͠ ͍·͢ʯ ‣
࠷ۙͷΈ ʮҰମԶ… ɹͲ͏ࣗݾհΛ͢Ε…ʁʯ
ݱࡏͷݱ(2025-03ݱࡏ) ‣ ༗ݶձࣾΦʔϓϯεϑΟΞ (CTO) ‣ גࣜձࣾΦτόϯΫ (όοΫΤϯυΤϯδχΞ) ‣ גࣜձࣾPR TIMES
(PHPεϖγϟϦετɺઌഐ) ‣ גࣜձࣾϦϯέʔδ (༯ਫ਼) ‣ ଞ֤ࣾ…(ΞʔΩςΫτίϯαϧPHPerຐআ͚ͳͲ)
ͦͷଞ൪એ ‣ Youtubeͷ uzulla chͰɺBaanSeenͳͲͷYoutubeͯ͠·͢ νϟϯωϧొͯ͠ʂग़ԋͯ͠ʂ ‣ ʮXdebugΛ։࢝͢Δ܅ʯͱ͍͏Chrome֦ுΛͭ͘Γ·ͨ͠ ੋඇ͔ͭͬͯ! ‣
BlueSkyʹɺͷPackagistࢹBotΛ෮׆ͤ͞·ͨ͠ʂ throwable.bsky.social (ݩͷxͷcall_user_func͔ΒϦϯΫͯ͋͠Γ·͢)
DISCLAIMER ‣ ͜ͷτʔΫɺ御社ͷαʔϏεʹPHPͷσʔϞϯΛಋೖ͢Δ ͜ͱΛお勧めしませんɻ ‣ (ݸਓαʔϏεͳΒɺԠԉ͠·͢ʂΏ͘Ώ͘ޚࣾʹ…ʁ) ‣ ࢲ͕ʮࣗPHPͰσʔϞϯΛॻ͘ΜͩʂʯͱݴΘΕͨΒɺ· ͣʮ΄͔ͷݴޠɺͬͯΈͨʁʯͱฉ͖·͢ɻ ‣
Δͱͯ͠ɺνʔϜͰेͳٞΛ͓͜ͳ͍·͠ΐ͏ɻ
ຊ σʔϞϯ࿉ ࣂ͍ͳΒ͠ ঌש ͷɺPHPer͚ΨΠυ
σʔϞϯͱʁ ‣ όοΫάϥϯυͰಈ࡞͢ΔৗறϓϩάϥϜ ‣ ࣗಈతʹىಈ͠ɺಛఆͷαʔϏελεΫΛܧଓతʹ࣮ߦ͠· ͢ ‣ Ϣʔβʔ͕ϩάΞτͯ͠ऴྃͤͣɺγεςϜγϟοτμϯ ·Ͱಈ࡞͠ଓ͚·͢ɻ ‣
ϢʔβʔͷΠϯλϥΫγϣϯͳ͠ʹಈ࡞͚ͭͮ͠Δ ‣ ྫ:Apache, Nginx, MySQL, PostgreSQL, crond, sshd
;ͭ͏ͷPHPͱσʔϞϯͷҧ͍ Start ϒϥβ Request Apache PHP script Start(reset) Process PHP
Response to ϒϥβ PHP script Finish(reset) ‣ ϦΫΤετ͕དྷͯϨεϙϯεΛฦ͢ɺຖճϦηοτ͞ΕΔ ‣ Θ͔Γ͍͢ʂ
όονͱσʔϞϯͷҧ͍ ‣ όονσʔϞϯʹʮࣅ͍ͯ·͢ʯ ‣ όονCronͳͲͰఆظతʹىಈͯ͠ऴྃ͢Δ ‣ Ұͷ࣮ߦͰ݁͢Δॲཧɺͱʹ͔͘ʮऴΘΓ͕͋Δʯ ‣ όονຖճऴྃ͢ΔͷͰσʔλετΞʹอଘͯ࣍͠ͷόον ʹඋ͑ΔͨΓ͢Δ
Cron։࢝ PHP script Start(reset) Process PHP Cronऴྃ PHP script Finish(reset)
Cron Cron
Batch(Cron)ͷݶքͱར ‣ ࠷খ࣮ߦִؒCronͳΒ1(௨ৗ) ‣ ಉ࣮࣌ߦͷ੍ޚ͕໘ɾ͍͠(ϩοΫ੍ޚ) ‣ CronʮʯదͰಈ͘
σʔϞϯ - Կ͔Λॲཧ͢ΔͷͰ͋Δ͕ɺϦΫΤετͱ͔Ϩεϙϯεඞ ਢͰͳ͍ɻ - NඵʹҰूܭͯ͠DBʹॻ͖ࠐΉͱ͔ - ঢ়ଶΛௐ͚͕ͭͮͯ͋ΕΞϥʔτΛSlackʹ͓͘Δͱ͔ - େྔͷσʔλΛʮԆॲཧͨ͠Γɾޮతʹɾॱ൪ʹʯॲཧ͢Δ
ͱ͔ - ͋ͱɺ(ඞཁ͕ͳ͚Ε)ऴྃ͠ͳ͍
MainLoop PHP script Start(reset) Systemd() Job ऴྃʁ Main Loop Entry
ॲཧA ॲཧN γάφϧ τϥοϓ NO ऴྃ ॲཧ YES killͳͲ γάφϧ ܧଓ ϑϥά ֬ೝ PHP script Finish( reset)
‣ Cronىಈִ͕ؒ͋Δ͕ɺσʔϞϯىಈִ͕ؒͳ͘ৗʹ࣮ߦ ‣ ىಈ͚ͭͮ͠ΔͷͰɺ࠶ଓɺΩϟογϡΛຖճಡΈࠐΉඞ ཁ͕ͳ͍ ‣ ʮఀࢭִؒʯ͕ͳ͍ͷͰɺଈ࠲ʹԠՄೳ ‣ ܧଓ͢ΔͷͰɺWebSocketͳͲͷଓΛҡ࣋Մೳ
σʔϞϯͷܽ ‣ ҆ఆͯ͠ಈ࡞͢ΔͷΛ࡞Δͷ͕͍͠ ͨͱ͑ϝϞϦϦʔΫɺDB࠶ଓॲཧͳͲ ‣ (όονී௨ͷWebϓϩάϥϜͱʹͨϊϦ) ‣ ҟৗऴྃͨ͠ͱ͖ʹ࠶ىಈͤͨ͞Γ͕໘ ‣ ଟ͘ͷ߹ɺόονREST
APIͰΑ͍Μ͚ ‣ ʑ…
ͳͥPHPͰσʔϞϯΛʁ(ݴ͍༁) ‣ PHPWebΞϓϦʴόονͱ͍͏Πϝʔδ͕ڧ͍ ‣ PHPͷࣝΛ׆͔͠ɺ༷ʑͳόοΫάϥϯυॲཧΛॻ͘ࣄ͕ Ͱ͖Ε… ‣ ΧοίΠΠ(ओ؍) ‣ ͜ͷลΓͷָ͓͠ΈޙͰ…
ૉͳσʔϞϯΛ࡞Δ 1. CLIεΫϦϓτͱͯ͠ىಈ 2. ϝΠϯϧʔϓͰܧଓ࣮ߦ 3. γάφϧϋϯυϦϯάͷ࣮
#"/usr/bin/env php <?php declare(strict_types=1); $running = true; pcntl_signal(SIGTERM, function ()
use (&$running) { // γάφϧϋϯυϥͷઃఆ echo "SIGTERMΛ͏͚ͱΓ·ͨ͠ɺऴྃ͠·͢" . PHP_EOL; $running = false; }); echo "σʔϞϯىಈ (PID: ".getmypid().")" . PHP_EOL; while ($running) { // ϝΠϯϧʔϓ pcntl_signal_dispatch(); // γάφϧΛड৴ͨ͠ॲཧ echo "." . PHP_EOL; sleep(5); /% CPUΛ༗͠ͳ͍Α͏ʹεϦʔϓ } echo "σʔϞϯऴྃ" . PHP_EOL;
$running = true; while ($running) { // ϝΠϯϧʔϓ pcntl_signal_dispatch(); //
γάφϧΛड৴ͨ͠ॲཧ echo "." . PHP_EOL; sleep(5); /" CPUΛ༗͠ͳ͍Α͏ʹεϦʔϓ } ‣ ແݶϧʔϓ(ϝΠϯϧʔϓ)͕͋Δ ‣ ʮා͍ʂʂʂʯ
$running = true; pcntl_signal(SIGTERM, function () use (&$running) { //
γάφϧϋϯυϥͷઃఆ echo "SIGTERMΛ͏͚ͱΓ·ͨ͠ɺऴྃ͠·͢" . PHP_EOL; $running = false; }); while ($running) { // ϝΠϯϧʔϓ pcntl_signal_dispatch(); // γάφϧΛड৴ͨ͠ॲཧ }
pcntl_signal(SIGTERM, function () use (&$running) { echo "SIGTERMΛ͏͚ͱΓ·ͨ͠ɺऴྃ͠·͢" . PHP_EOL;
$running = false; }); pcntl_signal(SIGHUP, function () use (&$running) { echo "SIGHUPΛ͏͚ͱΓ·ͨ͠ɺऴྃ͠·͢" . PHP_EOL; $running = false; }); pcntl_signal(SIGINT, function () use (&$running) { echo "SIGINTΛ͏͚ͱΓ·ͨ͠ɺऴྃ͠·͢" . PHP_EOL; $running = false; }); ‣ ड͚औΔγάφϧݸผઃఆ͕Ͱ͖·͢ ‣ γάφϧͷॲཧʮड͚औ͓͍ͬͯͯʯpcntl_signal_dispatch()Λݺͼग़ͯ͠ɺอཹதͷγάφϧΛॲ ཧ͠·͢ɻ͜ΕॏཁͳεςοϓͰɺ͜Ε͕ͳ͍ͱγάφϧϋϯυϥͰҙͷॲཧΛઃఆͰ͖·ͤΜɻ
γάφϧͷૹΓํ ‣ killίϚϯυͰૹ৴Ͱ͖·͢ɺPIDͷࢦఆ͕ඞཁͰ͢ ‣ PIDpsίϚϯυͰ֬ೝͰ͖·͢ $ kill {PID} $ kill
-HUP 1234 $ kill -TERM 1234 $ kill -USR1 1234 $ kill -KILL 1234 # ͜ΕOS͕ड͚औΓ·͢
ओཁͳγάφϧ ‣ SIGTERM (15): ਖ਼ৗऴྃཁٻ ‣ SIGINT (2): ΩʔϘʔυׂΓࠐΈʢCtrl+Cʣ ‣
SIGHUP (1): அɺ(Α͋͘Δͷ͕ઃఆ࠶ಡΈࠐΈ) ‣ SIGUSR1 (10), SIGUSR2 (12): Ϣʔβʔఆٛ ‣ SIGKILL (9): ڧ੍ऴྃʢัଊෆՄʣ
খ ‣ γάφϧͷҙຯʮࡉ͔͖͘·͍ͬͯ·ͤΜʯ ‣ Apache͕γάφϧͨΓͶ͍͑ͬͯͬͯɺWINCHΛѱ༻ͯ͠Δ͜ͱ Ұ෦Ͱ༗໊Ͱ͢Ͷ ‣ (WINCHΟϯυαΠζมߋͷγάφϧͰ͢) ‣ ࠷ѱɺεΫϩʔϧόʔ͕ͰΔ͚ͩͰɺApache͕ऴྃ͢ΔΜͰ͢ΑͶ…
‣ (ݹདྷɺCLIͰApacheΛىಈ͢Δਓ͕ؒ͏·ΕΔͱࢥͬͯͳ͔ͬͨ ΜͩΖ͏…)
None
খ:దͳऴྃॲཧ ‣ άϨʔεϑϧγϟοτμϯ ‣ ৽نॲཧΛఀࢭ͢Δ ‣ ਐߦதͷॲཧͷྃ͠ ‣ Ϧιʔεͷదͳղ์͠ ‣
ঢ়ଶͷอଘ͢Δ ‣ ऴྃεςʔλεͷ௨
pcntl_signal(SIGTERM, function () { echo "ऴྃॲཧΛ࣮ߦத..""; /$ ਐߦதͷδϣϒΛอଘ saveCurrentState(); /$
DBίωΫγϣϯΛΫϩʔζ DB:&getConn-(close(); echo "ਖ਼ৗʹऴྃ͠·ͨ͠ɻ"; exit 0; /$ TODO ·ͱʹ࣮ͤΑ }); ‣ ଞʹɺSIGTERMͳΒ register_shutdown_function Λ׆༻͢Δख͋Δ
σʔϞϯͷঌשํ๏ $ php daemon.php ‣ CLI ϓϩάϥϜͷΑ͏ʹͯ͠ঌש(ىಈ)͕Ͱ͖·͢ɻ ‣ λʔϛφϧΛด͡Δͱऴྃͯ͠͠·͏͜ͱͰ͢ ‣
։ൃʹศར͕ͩɺσʔϞϯΛࣂ͏ͱͯ͠ඍົ
ྫ: nohupΛ͏ํ๏ $ nohup php daemon.php & ‣ nohup: ϋϯάΞοϓγάφϧʢSIGHUPʣΛແࢹ͠·͢
‣ &: όοΫάϥϯυͰ࣮ߦ
ྫ: screen(tmux)ͳͲΛ͏ํ๏ # screenىಈ $ screen # σʔϞϯͳͲىಈ (screenͷதͰͷγΣϧ)$ php
daemon.php # Ctrl+A, DͰɺγΣϧΛΓͯ͠(σλον)ɺϓϩάϥϜΛऴྃͤͣʹϩάΞτͰ͖Δ # ޙͰ·ͨϩάΠϯͯ͠ɺ࠶։(Ξλον)Ͱ͖Δ $ screen -r ‣ ίωΫγϣϯ͕͖Εͯshell͕ऴྃͤͣɺ࠶ଓ͕Մೳ ‣ ։ൃ࣌ʹศར (࣮࣌ؒߦ͢ΔόονͰ͔ͭ͏ΑͶ) ‣ αʔόʔىಈ࣌ʹࣗಈىಈ͢ΔΑ͏ͳͷͰͳ͍
ίϯςφڥ FROM php:8.3-cli RUN docker-php-ext-install pcntl COPY -#from=composer /usr/bin/composer /usr/bin/composer
COPY . /keira WORKDIR /keira RUN composer install CMD /keira/bin/keira.php ‣ ͋ͱ docker run -it keira Ͱىಈ; ‣ ҙ: -it Φϓγϣϯ͕ͩɺ͠ͳ͍ͱγΣϧ͕ͳ͘ɺHUP͕Ͱ͖ͳ͍ͷͰऴ ྃผ్Δ͜ͱ
ຊ໋: systemdʹΑΔঌש ‣ SystemdLinuxͷαʔϏεཧσʔϞϯ [Unit] Description=PHP Sample Daemon After=network.target [Service]
Type=simple User=ww"-data ExecStart=/path/to/daemon.php Restart=on-failure RestartSec=5s Envfile=/etc/environment [Install] WantedBy=multi-user.target
systemctlʹΑΔૢ࡞ # αʔϏεͷొ $ systemctl enable php-daemon.service # αʔϏεͷ։࢝ $
systemctl start php-daemon.service # ঢ়ଶ֬ೝ $ systemctl status php-daemon.service # ఀࢭ $ systemctl stop php-daemon.service
Journalctl͍ͭͯ ‣ ϩάϑΝΠϧͷཧ͕ෆཁʂʢϩʔςʔγϣϯɺύʔϛογϣϯઃఆͳ Ͳʣ ‣ ߏԽσʔλͱͯ͠อଘ͞Εɺݕࡧ͕༰қ ‣ λΠϜελϯϓɺϗετ໊ɺϓϩηεIDͳͲͷϝλσʔλ͕ࣗಈతʹ ༩ ‣
γεςϜશମͷϩάͱ౷߹͞Εɺͷ૬ؔؔΛѲ͍͢͠ ‣ ϩάϨϕϧʹΑΔϑΟϧλϦϯά͕؆୯ ‣ ϩάग़ྗɺjournalctlίϚϯυͰ֬ೝͰ͖·͢ɻ
journalctlྫ # αʔϏεͷϩάΛදࣔ $ journalctl -u php-daemon.service # ࠷৽ͷϩάΛϑΥϩʔ $
journalctl -u php-daemon.service -f # ࠓͷϩάͷΈදࣔ $ journalctl -u php-daemon.service -#since today $ journalctl -u php-daemon.service -#since "2023-03-20 21:30:08" -#until "2023-03-20 22:30:08" # ΤϥʔϨϕϧͷϩάͷΈදࣔ $ journalctl -u php-daemon.service -p err # JSONܗࣜͰग़ྗ $ journalctl -u php-daemon.service -#output=json
ࢹͱ݈શੑ֬อ ‣ ϩάJournalctlͰࢹͰ͖Δ ‣ ʁʮͱ͍͑ɺҟৗऴྃͨ͠ΒͲ͏͢ΔͷʁPHP৴༻ͳ͍ ͠…ʯ ‣ ϔϧενΣοΫΛఆظతʹ࣮ߦͯ͠…ͱ͔͋Γ·͕͢ ‣ ͳΜͱɺҟৗऴྃͳΒSystemd͕࠶ىಈΛͬͯ͘Ε·
͢ʂʂʂ ศརʂʂʂʂ
༨ஊɿsystemdʹΑΔεέδϡʔϧ࣮ߦ ‣ ͱ͍͑ɺσʔϞϯϓϩάϥϜͳΜͯ࡞Γͨ͘ͳ͍ਓͷͨΊͷ systemdཱ͓ͪใ ‣ SystemdσʔϞϯͷىಈऴྃΛ͢Δ͚ͩͱ͓͍͖ɺεέ δϡʔϧ࣮ߦͰ͖ΔʹCronͷΘΓʹ͑Δ ‣ Cronͱ͕ͪͬͯϑΝΠϧΛઃஔͯ͠ཧ͢ΔͷͰɺIaCͱ૬ੑ͕ ྑ͍Ͱ͢
‣ Ұ࣌ఀࢭͱ͔ႈʹͰ͖·͢
systemdλΠϚʔϢχοτ # /etc/systemd/system/php-daemon.timer [Unit] Description=Run PHP daemon daily [Timer] OnCalendar=*-*-*
03:00:00 # ຖޕલ3࣌ʹ࣮ߦ AccuracySec=1s # ਫ਼Λ1ඵʹઃఆ [Install] WantedBy=timers.target
1Ҏʹυϯυϯ࣮ߦ͍ͨ͠߹ɺ͜ͷΑ͏ͳ͜ͱͰ͖·͢ [Unit] Description=My Job Service After=network.target [Service] Type=oneshot ExecStart=/path/to/your/script.sh [Unit]
Description=Run My Job every 10 seconds [Timer] OnUnitActiveSec=10s #લճͷ࣮ߦ͔Β10ඵޙʹ࠶࣮ߦ AccuracySec=1s [Install] WantedBy=timers.target
·ͱΊ ‣ Craft ‣ PHPͰσʔϞϯϓϩάϥϜ͕࡞Մೳ ‣ Taim ‣ γάφϧॲཧ͕ॏཁ ‣
summon ‣ systemdͳͲͷπʔϧΛ׆༻͠·͠ΐ͏
࣭λΠϜͦͷ1 ࣭͕͋͝ΕͲ͏ͧʂ
͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ PHPͰσʔϞϯΛʮࣂ͍ͳΒ͠ʯɺ࣮༻తʹӡ༻͠·͠ΐ͏ʂ (͔͖ͣ͞Μ https://x.com/i999rri τʔΫϨϏϡʔ͋Γ͕ͱ͏ʂ)
ͬͯɺ͜ΕͰऴΘΔΘ͚ͳ͍Ζ͕͍ʂʂʂ ͏ͣΒͪΌΜτʔΫΛΊΜͰʔʂʂʂ
͔͜͜Βָ͓͠ΈλΠϜ ‣ ʮPHPͰͭ͘ΒΕͨσʔϞϯͬͯͭΛΈͤͯ͋͛·͢Α…ʂʯ ‣ ʮ͑͑ͬPHPͰʂʁʯʮ͍ʂʂʯ ‣ ʮDemon(ѱຐ)Ͱͳ͘ʂʁʯʮ͍ʁʁʯ
Keira
None
‣ KeiraɺPHPͱamphpͰߏங͞ΕͨWebϞχλϦϯάΞϓϦ Ͱ͢ɻෳΛಉ࣌ࢹ͠ɺ͕ൃੜͨ͠ࡍʹϦΞϧλΠϜͰ௨ ͠·͢ɻ ‣ ϦΞϧλΠϜ௨ɿোൃੜ࣌ʹଈ࠲ʹSlack௨(※) ‣ WebSocketରԠɿϦΞϧλΠϜߋ৽ΛWebSocketͰఏڙ ‣ RESTful
APIɿγϯϓϧͳAPIͰࢹσʔλʹΞΫηε ‣ γάφϧ੍ޚɿUNIXγάφϧͰΞϓϦΛૢ࡞ ‣ ֤छΧελϚΠζࢹઃఆ
None
ࢲʮͲ͏Ͱ͢ʁʯ ʁʮJS Chart͓͔͘͠Ͷʁʯ ࢲʮຊ࣭Ͱͳ͍ʯ
ʢσʔϞϯͳΒͰͷʣӡ༻ʹ͑ΔϙΠϯτ ‣ Ұ࣌ఀࢭ͕ USR1,2 γάφϧͰͰ͖Δ ‣ ઃఆϑΝΠϧͷϦϩʔυΛHUPͰͰ͖Δ ‣ ࢹઌͷՃɺআɺҰ࣌ఀࢭͳͲΛαϙʔτ ‣
͜ͷ࣌ʹWebSocket͕அ͞ΕͨΓ͠·ͤΜ ‣ ౷ܭใ͖͑·ͤΜ ‣ ͳͥͳΒσʔϞϯͳͷͰ(ʁʁʁ)
None
Slack௨αϙʔτ͍ͯ͠Δʂ ‣ ͭΓ͕ͩͬͨɺࠓόάͬͯ·ͨ͠wwww ‣ ͳͷͰಈը͕ͳ͍ʂʂʂ ‣ ·͋ɺ͏͍ͨ͝ΜͩΑʂʂʂʂ৴ͯ͘͡Εʂʂʂʂ
Keiraͷίʔυͪ͜Β ‣ https://github.com/uzulla/Keira ‣ ҙ: ։ൃதͰ͢w ຊͷࢹʹ·ͩΘͳ͍Ͱ͍ͩ͘͞w
ͩ͜ΘΓϙΠϯτ ‣ WebsocketΛॲཧ͠ͳ͕Βɺࢹܧଓ͍ͯ͠Δ͠ɺREST API ͏͖͝·͢ʂ ‣ σʔϞϯͳͷͰɺDBͱ͔ෆཁʂ(σʔλมʹ͍ͬͯ·͢) ‣ 1ϓϩηεͳͷͰɺDockerίϯςφͱ͔Ͱಈ͔͢ͷָʑʂ (SystemdͷͲ͜ʹ…ʁ)
ίʔυ͓͠ΖϙΠϯτ ‣ amphpͳͷͰɺPure PHPͰ͢ (C֦ுෆཁ) ‣ ݁ߏಡΈ͔͍ͯ͋͘͢Γ·͢(ݸਓࠩ͋Δ) ‣ ApiServer.phpͱ͔ΈͯΈ͍ͯͩ͘͞ ‣
γάφϧॲཧɺUtil/SignalHandler.phpʹॻ͍ͯ͋Γ·͢ ‣ Application.php ͰɺػೳΛϚϯτ͍ͯ͘͠ͷ͕͓͠Ζ͍ ‣ Asyncͱ͔ɺCancelͱ͔͕͋Δ (ଞͷݴޠͬͯΔͻͱͳΒ͓͠Ζ͍Ͱ͠ΐ)
## Keira/src/Keira/Application.php /$ Create signal handler $this-&signalHandler = new SignalHandler($this-&configLoader,
$this-&monitorManager, $this-&appLogger); $this-&signalHandler-®ister(); /$ Create data retention manager $this-&dataRetention = new DataRetention($this-&monitorManager, $this-&appLogger); $this-&dataRetention-&start(); /$ Create API server $this-&apiServer = new ApiServer('0.0.0.0', 8080, $this-&monitorManager, $this-&appLogger); $this-&apiServer-&start(); /$ Start monitoring $this-&monitorManager-&start();
## KKeira/src/Keira/WebSocket/WebSocketHandler.php public function handleClient( ): void { $this-%gateway-%addClient($client); try
{ foreach ($client as $message) { $payload = $message; $this-%logger-%info("[INFO][APP] Received WebSocket message: {$payload}"); } } catch (\Throwable $e) { $this-%logger-%error("[ERROR][APP] WebSocket error: {$e-%getMessage()}"); } finally { $this-%logger-%info("[INFO][APP] WebSocket client disconnected"); } } /** * Broadcast monitor result to all connected clients *( private function broadcastResult(MonitorResult $result): void { $payload = json_encode($result-%toArray()); if ($payload) { $this-%gateway-%broadcastText($payload); } }
## Keira/src/Keira/Api/ApiServer.php private function registerRoutes(): void { /% GET /monitors
- List all monitors $this-'router-'addRoute('GET', '/monitors', new ClosureRequestHandler( function ($request) { $handler = new MonitorsHandler($this-'monitorManager); return $handler($request); } )); /% GET /ws-test - WebSocket test page $this-'router-'addRoute('GET', '/ws-test', new ClosureRequestHandler( function ($request) { $templatePath = '/websocket-test.html'; if (!file_exists($templatePath)) { return new \Amp\Http\Server\Response( status: 500, headers: ['Content-Type' =+ 'text/plain'], body: 'Template file not found' ); } $html = file_get_contents($templatePath); return new \Amp\Http\Server\Response( status: 200, headers: ['Content-Type' =+ 'text/html'], body: $html ); } ));
## Keira/src/Keira/Util/SignalHandler.php public function register(): void { /% SIGHUP: Reload
configuration async(function () { while (true) { try { trapSignal(\SIGHUP); $this-(handleSighup(); } catch (SignalException $e) { /% Signal handler was cancelled break; } } });
·ͱΊ2 ‣ PHPͰɺ࣮༻తͳσʔϞϯ͕࡞ΕΔʂ ‣ ͔͠ɺҊ֎ಡΊΔʂ(ݸਓࠩ͋Γ·͢) ‣ νϡʔχϯά(CPUෛՙ)ͱ͔·ͩ·ͩͰ͢ɻ Ͱɺಈ͘͜ͱ͕Θ͔ΔɺͦΕ͕࢝·ΓͰ͢ʂʂʂ
ʮΦϨͨͪ·ͩΓ࢝Ί͔ͨΓ͔ͩΒͳɻ ͜ͷͯ͠ͳ͘ԕ͍σʔϞϯ࿉ΛΑ…!ʯ
One more thing...
DB-monitor ‣ https://github.com/uzulla/db-monitor ‣ ʮՔಇதͷσʔλϕʔεͷ౷ܭใΛϦΞϧλΠϜʹදࣔ͠ɺվળʹ ཱͯΔใΛऔಘ͢ΔπʔϧͰ͢ʯ ‣ DBʹৗ࣌ଓͯ͠ɺΫΤϦΛϞχλʔ͢ΔπʔϧΛͭ͘Γ͔ͨͬͨ ‣ ʮPHPͰʂʂʂʂʂʂʂʂʂʯ
‣ ͳͥͳΒPHPͳΒɺ৭ʑͳਖ਼نදݱͱָ͔͕ʹ͑Δ͠ɺίʔυ͕ಡΈ ͍͔͢Β(ݸਓࠩ͋Δ) ‣ ͜ΕamphpͰॻ͍ͯ·͢
None
None
͓ΘΓ ‣ ࣭͋Γ·͔͢ʁ ‣ ͳ͍ͳΒɺthrowable.bsky.social ͷσϞͰ͢Δ