3

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

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

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

我们的方法很灵活,但因为我们在 Windows 平台上运行,所以 BATCH 和 Powershell 是首选解决方案。

澄清:

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

资源:

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

4

3 回答 3

5

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

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

所以你只需要确保你从不直接调用 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 队列。如果收到多个重叠的请求,那么下一个进程将随机抽取。但是这些过程将被序列化。

编辑:
在编辑之前,我已经阅读了 splattered bits 的原始答案。他质疑文件锁定在远程机器上是否可靠。我进行了一些快速的 Google 搜索,但在 UNC 路径上的文件锁定似乎确实存在一些问题。如果遇到问题,您可能会更幸运地重定向到映射驱动器号上的文件,而不是直接通过 UNC 路径。这都是理论 - 我没有做过任何测试。在提交此解决方案之前,请务必进行充分的测试。请注意,PUSHD 是一种在不知道可用驱动器号的情况下临时将驱动器号分配给 UNC 路径的便捷方法。POPD 将取消映射驱动器分配。

于 2013-08-01T22:14:11.903 回答
0

为了锁定对网络驱动器的访问,您需要一个与您的 CI 服务对话的第三方。然后,该第三方将处理对网络驱动器的访问。该第三方可能是:

  • MSMQ
  • 数据库表中的行
  • 符号服务器上的 WCF 服务运行symstore并且您的 CCNet 构建与其对话以触发symstore
  • 符号服务器上的 CCNet,带有可以远程触发的项目/作业
  • 可以从 CI 服务器远程触发的符号服务器上的计划作业
于 2013-08-01T19:11:48.870 回答
-1

使用共享目录中的文件作为信号量以避免并发执行。

:checkfile
if exist %cidir%\sem.txt goto :wait10secs
echo gotit! >%cidir%\sem.txt
doit
del %cidir%\sem.txt
goto :eof
:wait10secs
ing 192.0.2.2 -n 1 -w 10000 > nul
goto :checkfile

准备好调试您的批次可能失败的所有奇怪方式以及所有令人讨厌的赛车条件。

于 2013-08-01T19:05:56.407 回答