首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用SignalR通知应用程序用户系统正在部署过程中

如何使用SignalR通知应用程序用户系统正在部署过程中
EN

Stack Overflow用户
提问于 2022-03-30 12:59:30
回答 1查看 179关注 0票数 1

是否有办法实时通知系统用户系统正在部署过程中(发布到生产)?目的是防止他们开始执行原子操作?该系统是一个基于ASP.NET的系统,它已经具有SignalR Dlls,但我不知道如何在我知道系统正在部署的应用程序中找到“源”。

EN

回答 1

Stack Overflow用户

发布于 2022-03-31 07:56:12

这在很大程度上取决于您的部署过程,但我在以下方面实现了类似的目标:

我在一个控制器中创建了一个名为AnnounceUpdate的方法

代码语言:javascript
复制
[HttpPost("announce-update")]
public async Task<IActionResult> AnnounceUpdate([FromQuery] int secondsUntilUpdate, string updateToken)
{
    await _tenantService.AnnounceUpdate(secondsUntilUpdate, updateToken);
    return Ok();
}

控制器方法在更新前的秒数,以及一个秘密令牌,以确保不只是任何人都可以调用这个端点。

我们的想法是,我们将在部署之前调用此控制器,以宣布挂起的部署。我使用Azure进行部署,因此我能够创建一个发布任务,该任务自动运行以下PowerShell代码来调用我的端点:

代码语言:javascript
复制
$domain = $env:LOCALURL;
$updateToken = $env:UPDATETOKEN;
$minutesTillUpdate = 5;

$secondsUntilUpdate = $minutesTillUpdate * 60;
$len = $secondsUntilUpdate / 10;

#notify users every 10 seconds about update
for($num =1; $num -le $len; $num++)
{
    $url = "$domain/api/v1/Tenant/announce-update?secondsUntilUpdate=$secondsUntilUpdate&updateToken=$updateToken";

    $r = Invoke-WebRequest $url -Method Post -UseBasicParsing;
    $minsLeft = [math]::Floor($secondsUntilUpdate/60);
    $secsLeft = $secondsUntilUpdate - $minsLeft * 60;

    $timeLeft;
    if($minsLeft -eq 0){
        $timeLeft = "$secsLeft seconds";
    }else{
        if($secsLeft -eq 0){
            $timeLeft = "$minsLeft minute(s)";
        }else{
            $timeLeft = "$minsLeft minute(s) $secsLeft seconds";
        }
    };

    $code = $r.StatusCode;

    Write-Output "";
    Write-Output "Notified users $num/$len times.";
    Write-Output "Response: $code.";
    Write-Output "$timeLeft remaining."
    Write-Output "_________________________________"

    Start-Sleep -Seconds 10;

    $secondsUntilUpdate = $secondsUntilUpdate - 10;
}

Write-Output "Allowing users to log out.";
Write-Output "";

Start-Sleep -Seconds 1;

Write-Output "Users notfied! Proceeding with update.";

正如您所看到的,在脚本上,我已经设置了更新的时间是5分钟。然后,在5分钟的时间内,每10秒调用我的AnnounceUpdate端点。我这样做是因为如果我宣布一个5分钟后将发生的更新,然后2分钟后有人连接,他们将不会看到更新消息。在客户端,当客户端收到更新通知时,我将一个名为updatePending的变量设置为true,这样他们就不会继续每10秒收到一条消息。只有尚未看到更新消息的客户端才会收到更新消息。

在租户服务中,我有以下代码:

代码语言:javascript
复制
public async Task AnnounceUpdate(int secondsUntilUpdate, string updateToken)
{
    if (updateToken != _apiSettings.UpdateToken) throw new ApiException("Invalid update token");
    await _realTimeHubWrapper.AnnouncePendingUpdate(secondsUntilUpdate);
}

我只需检查令牌是否有效,然后通过conitnue调用集线器包装器。

集线器包装器是signalR的集线器上下文的实现,它允许在代码中调用signalR方法。更多信息可以阅读https://learn.microsoft.com/en-us/aspnet/core/signalr/hubcontext?view=aspnetcore-6.0#:%7E:text=The%20SignalR%20hub%20is%20the%20core%20abstraction%20for,send%20notifications%20to%20clients%20from%20outside%20a%20hub.

在集线器包装器中,我有以下方法:

代码语言:javascript
复制
public Task AnnouncePendingUpdate(int secondsUntilUpdate) =>
_hubContext.Clients.All.SendAsync("UpdatePending", secondsUntilUpdate);

在客户端,我设置了这个处理程序:

代码语言:javascript
复制
  // When an update is on the way, clients will be notified every 10 seconds.
  private listenForUpdateAnnouncements() {
    this.hubConnection.on(
      'PendingUpdate', (secondsUntilUpdate: number) => {
        if (!this.updatePending) {
          const updateTime = currentTimeString(true, secondsUntilUpdate);
          const msToUpdate = secondsUntilUpdate * 1000;

          const message =
            secondsUntilUpdate < 60
              ? `The LMS will update in ${secondsUntilUpdate} seconds.
        \n\nPlease save your work and close this page to avoid any loss of data.`
              : `The LMS is ready for an update.
        \n\nThe update will start at ${updateTime}.
        \n\nPlease save your work and close this page to avoid any loss of data.`;

          this.toastService.showWarning(message, msToUpdate);

          this.updatePending = true;

          setTimeout(() => {
            this.authService.logout(true, null, true);
            this.stopConnection();
          }, msToUpdate);
        }
      }
    );
  }

我向客户端显示了一条祝酒词,通知他们更新的消息。然后,我设置了一个超时(使用secondsUntilUpdate__的值),它将记录用户退出并停止连接。这是专门为我的用例。现在你可以做你想做的任何事

总之,逻辑流程是:

PowerShell脚本->控制器->服务->集线器包装器->客户端

主要的方法是,我们仍然需要触发对端点的调用来宣布更新。我很幸运能够在我的发布过程中自动运行它。如果您正在手动发布和复制已发布的代码,那么您可以手动运行PowerShell脚本,然后在完成后进行部署?

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71677714

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档