我们正在努力将一个步骤集成到我们的持续集成(CI)服务器(CruiseControl.NET)中。我们希望将在构建过程中生成的调试符号*.pdb注册到Microsoft Symbol Server中。正如Microsoft所实现的,符号服务器是Visual Studio用于查找C++ / C#可执行文件的*.pdb调试符号的目录结构。 Microsoft提供了一个命令symstore,该命令将调试符号放在一个目录中,并在适当时填充中央符号存储目录。

问题是symstore明确指出并发运行是不安全的。

我们可以尝试哪些方法或策略来禁止通过BATCH或Powershell脚本同时执行symstore命令?

我们在方法上很灵活,但是由于我们在Windows平台上运行,BATCH和Powershell是首选解决方案。

说明:

对于我们的用例,symstore需要可从两个不同的CI服务器运行,这会将符号保存在公共(public)网络驱动器上。

资源:

symstore::
http://msdn.microsoft.com/en-us/library/windows/desktop/ms681417(v=vs.85).aspx

最佳答案

您可以将锁定文件用作简单的信号量来序列化事件。当您将stdout重定向到批处理文件中的文件时,它将在该文件上建立排他写锁定。没有其他进程可以打开同一文件进行写访问。无论过程如何结束(干净退出,CTRL-C,异常失败等),该锁将在过程结束时自动释放。

批处理文件可以尝试将9重定向到锁定文件,如果失败,则循环返回直到成功。 symstore命令仅在锁定到位时运行。使用了非标准的文件句柄(流?),以便该锁不会干扰stdin,stdout或stderr处理。

因此,您只需要确保您从未直接调用symstore。相反,您总是通过批处理脚本来调用它。类似于以下内容(serializeSymstore.bat):

@echo off
setlocal

:loop

:: Save stderr definition and redirect stderr to nul
:: to hide possible redirection error when establishing lock.
8>&2 2>nul (

  %= Attempt to establish the lock and restore stderr =%
  9>"\\centralServer\somePath\symstore.lock" 2>&8 (

    %= If got here then lock is established throughout all commands =%
    %= in this set of parentheses.                                  =%

    %= Execute your command =%
    symstore %*

    %= Save the return code =%
    call set "rtnCd=%%errorlevel%%"

    %= The next command is a very fast way to clear the ERRORLEVEL. =%
    %= We don't want symstore failure to trigger a loop.            =%
    (call )
  )

) || (
  %= If entered here then failed to establish lock.                 =%
  %= Wait 1 second and then loop back to retry.                     =%
  %= Replace with PING delay if TIMEOUT not universally available.  =%
  timeout 1 /nobreak >nul
  goto loop
)

:: Exit with appropriate return code
exit /b %rtnCd%

没有注释,它将变成一小段代码
@echo off
setlocal

:loop
8>&2 2>nul (
  9>"\\centralServer\somePath\symstore.lock" 2>&8 (
    symstore %*
    call set "rtnCd=%%errorlevel%%"
    (call )
  )
) || (
  timeout 1 /nobreak >nul
  goto loop
)
exit /b %rtnCd%

我发现这种原始而简单的策略在许多项目中都非常有效。我必须承认,我还没有测试远程计算机上的锁定和释放特性。但是我相信,只要所有机器都是Windows,它就应该可靠。

我知道的唯一缺点是没有FIFO队列。如果收到了多个重叠的请求,那么接下来要去哪个进程是一个随机的幸运。但是这些过程将被序列化。

编辑:在编辑之前,我已经阅读了飞溅的位的原始答案。他质疑文件锁定在远程计算机上是否可靠。我做了一些快速的Google搜索,但UNC路径上的文件锁定确实出现了一些问题。如果您遇到问题,则最好运气重定向到映射驱动器号上的文件,而不是直接通过UNC路径。这全都是理论-我没有做任何测试。在提交此解决方案之前,请确保进行足够的测试。请注意,PUSHD是在不知道可用的驱动器号的情况下将驱动器号临时分配给UNC路径的便捷方法。 POPD将取消映射驱动器分配。

08-07 17:03