如何配置用Go编写的Windows服务的失败操作? [英] How do I configure failure actions of a Windows service written in Go?

查看:722
本文介绍了如何配置用Go编写的Windows服务的失败操作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 golang.org/x/sys/windows/svc 软件包在Go中编写Windows服务。



到目前为止,这一切都很好,很容易开始,我很喜欢它。



我写了一些自动更新功能,我我希望服务在完成更新时自动重启。



我试过产生一个进程,使用重新启动服务, SCM ,但它记录了一条错误消息,这似乎是在尝试以本地系统身份运行时控制服务。

 服务进程无法连接到服务控制器。 

更好/更简单的方法似乎是 os.Exit(1) 并将服务失败操作设置为重新启动失败,这非常出色! / p>

唯一的问题是,似乎没有使用Go以编程方式配置这些选项的功能。



我已经做了一些挖掘,看起来他们是通过在 advapi32.dll 中将结构传递给 ChangeServiceConfig2 - 如何创建在崩溃时重新启动的服务


$ b

golang / sys / blob / master / windows / svc / mgr / config.go - func updateDescription(句柄窗口。代码已经调用了 windows.ChangeServiceConfig2 ,它是一个指向DLL调用的链接。



Microsoft文档用于 SERVIC E_FAILURE_ACTIONS 结构为此处



我很难弄清楚如何使用Go构建和传递结构 - 有没有人有任何见解?

解决方案

),再加上通过现有Go Windows服务接口的源代码阅读,我想出了自己的答案,我将在下面进行介绍。 / p>

对于使用Windows DLL的类型引用,MSDN文档是 here



我的代码如下所示:

  import(
unsafe
golang.org/x/sys/windows


const(
SC_ACTION_NONE = 0
SC_ACTION_RESTART = 1
SC_ACTION_REBOOT = 2
SC_ACTION_RUN_COMMAND = 3

SERVICE_CONFIG_FAILURE_ACTIONS = 2


类型SERVICE_FAILURE_ACTIONS结构{
ResetPeriod uint32
RebootMsg * uint16
命令* uint16
ActionsCount uint32
操作uintptr
}

类型SC_ACTION结构{
类型uint32
延迟uint32
}

func setServiceFailureActions(句柄windows.Handle)错误{
t:= [] SC_ACTION {
{Type:SC_ACTION_RESTART,Delay:uint32(1000)},
{Type:SC_ACTION_RESTART,Delay:uint32(10000)},
{Type:SC_ACTION_RESTART,Delay:uint32 (60000)},
}
m:= SERVICE_FAILURE_ACTIONS {ResetPeriod:uint32(60),ActionsCount:uint32(3),操作:uintptr (unsafe.Pointer(& t [0]))}

return windows.ChangeServiceConfig2(handle,SERVICE_CONFIG_FAILURE_ACTIONS,(* byte)(unsafe.Pointer(& m)))
}

在我的基本示例中,您需要传递一个服务句柄,然后它将设置失败操作到硬编码默认值:


  1. 1秒后首次重新启动。
  2. 重新启动
  3. 在第60秒后重新开始第三次以及任何后续时间。
  4. 在60秒后重置故障计数器。
  5. / li>

我刚刚测试过,它似乎可以正常工作。


I'm writing a Windows Service in Go using the golang.org/x/sys/windows/svc package.

So far, it's all working great and so easy to get started with, I love it.

I've written in some auto update functionality and I'm wanting the service to restart itself when it has completed an update.

I've tried spawning a process that will restart the service using the SCM, but it logs an error message which seems to be to do with trying to control the service while running as Local System.

The service process could not connect to the service controller. 

A better/easier way seems to be to os.Exit(1) and have the service Failure Actions set to Restart on Failure, which works brilliantly!

The only trouble is, there doesn't seem to be the functionality to configure those options programatically using Go.

I've done some digging and it looks like they are configured by passing a struct to ChangeServiceConfig2 in advapi32.dll - How to create service which restarts on crash

In golang/sys/blob/master/windows/svc/mgr/config.go - func updateDescription(handle windows.Handle, desc string) error

The code already calls windows.ChangeServiceConfig2 which is a link to the DLL call.

And the Microsoft docs for the SERVICE_FAILURE_ACTIONS struct are here.

I'm having trouble figuring out how to build and pass that struct using Go - does anyone have any insights?

解决方案

After some guidance from here, plus reading through the source code for the existing Go Windows Service interface, I came up with my own answer, which I'll try to document below.

For type reference when working with the Windows DLLs, the MSDN docs are here.

My code looks like this:

import (
    "unsafe"
    "golang.org/x/sys/windows"
)

const (
    SC_ACTION_NONE                      = 0
    SC_ACTION_RESTART                   = 1
    SC_ACTION_REBOOT                    = 2
    SC_ACTION_RUN_COMMAND               = 3

    SERVICE_CONFIG_FAILURE_ACTIONS      = 2
)

type SERVICE_FAILURE_ACTIONS struct {
    ResetPeriod     uint32
    RebootMsg       *uint16
    Command         *uint16
    ActionsCount    uint32
    Actions         uintptr
}

type SC_ACTION struct {
    Type            uint32
    Delay           uint32
}

func setServiceFailureActions(handle windows.Handle) error {
    t := []SC_ACTION{
        { Type: SC_ACTION_RESTART, Delay: uint32(1000) },
        { Type: SC_ACTION_RESTART, Delay: uint32(10000) },
        { Type: SC_ACTION_RESTART, Delay: uint32(60000) },
    }
    m := SERVICE_FAILURE_ACTIONS{ ResetPeriod: uint32(60), ActionsCount: uint32(3), Actions: uintptr(unsafe.Pointer(&t[0])) }

    return windows.ChangeServiceConfig2(handle, SERVICE_CONFIG_FAILURE_ACTIONS, (*byte)(unsafe.Pointer(&m)))
}

In my basic example, you need to pass a Service Handle, then it'll set the failure actions to a hard coded default of:

  1. Restart the first time after 1 second.
  2. Restart the second time after 10 seconds.
  3. Restart the third time and any subsequent times after 60 seconds.
  4. Reset the failure counter after 60 seconds.

I've just tested and it seems to work ok.

这篇关于如何配置用Go编写的Windows服务的失败操作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆