我在Haskell中编写了一个systemd套接字激活服务。 这个想法是服务应该在消息发送到它的套接字时自动启动,服务应该处理在套接字上等待的所有消息,然后退出。
注意:处理所有等待消息(而不是永久运行)后服务应该关闭的原因是套接字激活之间应该有几个小时或几天的时间。
部署-trigger.socket:
[Socket] ListenStream=/var/run/deploy-trigger.socket [Install] WantedBy=sockets.target部署-trigger.service:
[Service] ExecStart=/home/user4301448/.local/bin/deploy-trigger-exe StartLimitInterval=0Main.hs
{-# LANGUAGE OverloadedStrings #-} module Main where import Control.Monad (forever) import qualified Data.ByteString.Char8 as BS (putStrLn) import Data.Foldable (foldl') import Network.Socket (withSocketsDo, accept, close, SockAddr(SockAddrUnix), Socket) import Network.Socket.ByteString (recv) import Network.Socket.Activation (getActivatedSockets) import System.Exit (exitWith, ExitCode(..)) main :: IO () main = withSocketsDo $ forever $ getActivatedSockets >>= processSocks processSocks :: Maybe [Socket] -> IO () processSocks (Just socks) = do putStrLn "Got socket(s)." traverse_ (\sock -> accept sock >>= printMsgFromSock) socks putStrLn "Finished processing socket(s)." processSocks Nothing = do putStrLn "Received no socket(s)." exitWith ExitSuccess printMsgFromSock :: (Socket, SockAddr) -> IO () printMsgFromSock (sock, sockaddr) = do msg <- recv sock 2048 case sockaddr of SockAddrUnix s -> putStrLn ("Printing message from socket: " ++ s) _ -> putStrLn "Printing message from something that is not a UNIX socket." BS.putStrLn msg close sock编译时(并使用stack install ),然后通过使用以下命令向套接字发送一些文本来激活:
printf 'Hello world\r\n' | nc -U /var/run/deploy-trigger.socket以下是打印到systemd日志(我正在使用journalctl -f来观看日志):
systemd[1]: Starting deploy-trigger.service...没有其他印刷品; 该过程将永久运行并最大化所有计算机的CPU核心。 为什么会发生这种情况,并且是否有办法将行为改变为第一段中描述的行为?
将main更改为以下内容:
main = withSocketsDo $ getActivatedSockets >>= processSocks从而forever删除,再次stack install并发送一些文本到套接字将以下内容打印到日志中:
systemd[1]: Starting deploy-trigger.service... deploy-trigger-exe[14800]: Got socket(s). deploy-trigger-exe[14800]: Printing message from socket: deploy-trigger-exe[14800]: Hello world deploy-trigger-exe[14800]: Finished processing socket(s). systemd[1]: Started deploy-trigger.service.deploy-trigger-exe然后干净地退出。 这样做的缺点是二进制似乎是由systemd对发送到套接字的每条消息运行的,这是不可取的。
注意:我怀疑这个问题根源于我对UNIX套接字的无能。 任何有关我误解的支持信息的答案,纠正我的duff术语将是一项奖励。
I have written a systemd socket activated service in Haskell. The idea is the service should be started automatically when a message is sent to its socket, the service should process all messages waiting on the socket and then exit.
Note: the reason the service should close after processing all waiting messages (as opposed to running forever) is there shall be several hours or days between socket activations.
deploy-trigger.socket:
[Socket] ListenStream=/var/run/deploy-trigger.socket [Install] WantedBy=sockets.targetdeploy-trigger.service:
[Service] ExecStart=/home/user4301448/.local/bin/deploy-trigger-exe StartLimitInterval=0Main.hs
{-# LANGUAGE OverloadedStrings #-} module Main where import Control.Monad (forever) import qualified Data.ByteString.Char8 as BS (putStrLn) import Data.Foldable (foldl') import Network.Socket (withSocketsDo, accept, close, SockAddr(SockAddrUnix), Socket) import Network.Socket.ByteString (recv) import Network.Socket.Activation (getActivatedSockets) import System.Exit (exitWith, ExitCode(..)) main :: IO () main = withSocketsDo $ forever $ getActivatedSockets >>= processSocks processSocks :: Maybe [Socket] -> IO () processSocks (Just socks) = do putStrLn "Got socket(s)." traverse_ (\sock -> accept sock >>= printMsgFromSock) socks putStrLn "Finished processing socket(s)." processSocks Nothing = do putStrLn "Received no socket(s)." exitWith ExitSuccess printMsgFromSock :: (Socket, SockAddr) -> IO () printMsgFromSock (sock, sockaddr) = do msg <- recv sock 2048 case sockaddr of SockAddrUnix s -> putStrLn ("Printing message from socket: " ++ s) _ -> putStrLn "Printing message from something that is not a UNIX socket." BS.putStrLn msg close sockWhen compiled (and installed with stack install), then activated by sending some text to the socket using the following command:
printf 'Hello world\r\n' | nc -U /var/run/deploy-trigger.socketthe following is printed to the systemd journal (I'm using journalctl -f to watch the logs):
systemd[1]: Starting deploy-trigger.service...nothing else is printed; the process runs forever and maxes out all the computer's CPU cores. Why does this happen and is there a way to change the behaviour to that described in the first paragraph?
Changing main to the following:
main = withSocketsDo $ getActivatedSockets >>= processSocksthus removing forever, stack installing again and sending some text to the socket prints the following to the journal:
systemd[1]: Starting deploy-trigger.service... deploy-trigger-exe[14800]: Got socket(s). deploy-trigger-exe[14800]: Printing message from socket: deploy-trigger-exe[14800]: Hello world deploy-trigger-exe[14800]: Finished processing socket(s). systemd[1]: Started deploy-trigger.service.deploy-trigger-exe then exits cleanly. The downside to this is the binary appears to be run by systemd for every message sent to the socket, which is not desirable.
Note: I suspect the issue is rooted in my incompetence regarding UNIX sockets. Any answers with supporting information on what I'm misunderstanding, correcting my duff terminology would be a bonus.
更多推荐
发布评论