きよくらの備忘録

「三日坊主と呼ばせない!日記」改め。主にソフトウェア開発関連の話題。

Hangfireを使ってみる (1):とりあえず触ってみる

最近 Hangfire について調査・検証しているのでメモ。

Hangfireとは

Hangfireは.NET向けのバックグランド・タスクのライブラリです。

www.hangfire.io

ストーレージにタスクをキューイングして、非同期に実行させることができます。即時実行だけでなく、cronっぽい感じで定期実行したりもできる模様。 OWIN Middleware としてASP.NETで利用できるほか、コンソール/WPF/Windows Form/Windows サービス等など……でも使えます。

 

今回から予定している一連のエントリは『ASP.NETのWebアプリケーションから重たい処理(例:集計帳票作成処理)を非同期実行させる』という観点での調査検証に基づいています。ですので、ある程度方より(?)がある点はご了承ください。

Hangfireを構成するコンポーネント

Hangfireはざっくりと以下のようなコンポーネントで構成されています。

コンポーネント 役割 典型的な実装
Hangfire Client Jobをキューへ登録 ASP.NET等, ユーザーが操作するアプリ
Job Storage Jobのキュー,その他管理情報を格納 SQL Server / Redis 等
Hangfire Server キュー上のJobの実行 ASP.NET(バックグラウンド) / Windowsサービス等

 

Hangfire ClientとHangfire Serverは同一のプロセス上で実装可能です*1。 そのほか、ASP.NET用にビルトインされていてるダッシュボード機能があり、jobの状況のモニタリングや再実行などの操作を行うことができます。

とりあえず試してみる

チュートリアル的に一番シンプルで試しやすい構成として、『ClientとServerの双方を同一のASP.NET Webアプリケーションに実装』するパターンを試してみます。

f:id:kiyokura:20170803113448p:plain:w300

https://github.com/kiyokura/HangfireSample01/tree/step01

基本構成

とりあえずこんな感じでやってみました。

  • Visual Studio 2015
  • ASP.NET MVC 5
  • SQL Server 2016

実装手順

1. SQL ServerでHangfire用のDBを作成

Jobストレージとして利用するデータベースが必要なので適当に作成しておきます。データベース内にはHangfireスキーマといくつか専用のテーブルが作成されます*2

2. ASP.NET MVCのプロジェクトを作成する

Visual Studio 2015で適当にASP.NET MVCのプロジェクトを作成しました。 f:id:kiyokura:20170803115757p:plain:w300

3. NuGetでHangfireのパッケージを取得

NuGetでHangfireを取り込みます。コマンドラインからだとInstall-Package HangfireでOK。

f:id:kiyokura:20170803120224p:plain

4. OWINスタートアップを記述

Hangire の最低限必要な設定をOWINスタートアップで行うように記述します。Webアプリケーションプロジェクトの直下にOWIN Startupクラス「Startup.cs」を追加して、以下のように書きました。

using Hangfire;
using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(HangfireSample01.Startup))]

namespace HangfireSample01
{
  public class Startup
  {
    public void Configuration(IAppBuilder app)
    {
      // 接続文字列は環境に応じて変えること
      var constr = @"Data Source=localhost;Initial Catalog=HangfireJob;Integrated Security=True";
      GlobalConfiguration.Configuration.UseSqlServerStorage(constr);

      app.UseHangfireDashboard();
      app.UseHangfireServer();
    }
  }
}
5. Jobの登録処理を記述

最後に実際にjobをキューに登録する処理を書きます。既存のHomeControllerのIndexアクションメソッドに、とりあえずコンソールに文字を出力するだけの単純な処理をjobとして登録するように書いてみました。

using Hangfire;
using System;
using System.Web.Mvc;

namespace HangfireSample01.Controllers
{
  public class HomeController : Controller
  {
    public ActionResult Index()
    {
      // Hangfireでjobをキューに登録
      BackgroundJob.Enqueue(() => Console.WriteLine("Simple Job"));
      return View();
    }

    public ActionResult About()
    {
      ViewBag.Message = "Your application description page.";
      return View();
    }

    public ActionResult Contact()
    {
      ViewBag.Message = "Your contact page.";

      return View();
    }
  }
}

実行して確認する

準備が終わったので実行してみます。

1.WebアプリケーションをF5で実行

F5でデバッグ実行を開始すると見慣れた(?)ASP.NET MVCのテンプレートのホーム画面が表示されます。このとき、Home/Indexアクションメソッドが実行されているので裏ではキューにjobが登録され、そして実行されているはずです。

次の手順でそのあたりを確認してみます。

2.Hangfireダッシュボードを表示

Hangfire組み込みのダッシュボードを利用してjobの状況を確認してみます。hangfireダッシュボードは、アプリケーションルート+/hangfireというURLでアクセスできます。今回のようにIIS Expressでローカル実行している場合は例えば以下のようになります

  • http://localhost:61828/hangfire (※ポート番号は環境によって変わります)

アクセスできるとこんな感じのダッシュボードが表示されます。 f:id:kiyokura:20170803122544p:plain

3.jobの実行状況を確認

ダッシュボードで実際のjobがどのようになっているかを確認します。 メニューから[jobs]-[Succeeded]とたどっていくと、成功したジョブ一覧に先ほど登録したjobが並んでいるのが見えました。

f:id:kiyokura:20170803122848p:plain

さらにjob名をクリックすると詳細情報が見れます。 f:id:kiyokura:20170803123351p:plain

4.データベース(Job Storage)を確認

最後に、Job Storageとなっているデータベースを簡単に確認してみました。

SSMSで該当のデータベースを開いてみると、こんな感じでテーブルが作成され、例えばHangfire.Jobテーブルにはこんな形でJobが格納されているのが分かります。 f:id:kiyokura:20170803123619p:plain

ここまでのまとめ

Hangfireのクイックスタート的な感じでとりあえず手元で基本的な動作をさせてみました。というか、オフィシャルのドキュメントのQuick Startにあるそのままです。

なお、ここまでのサンプルコードは以下にあります

github.com

このHangfire ServerもASP.NETのインプロセスで動かすモデルの場合、ASP.NETの標準仕組の HostingEnvironment.QueueBackgroundWorkItem と似ているようにも見えます。しかしキューが永続化されているためjobのトレースやリトライ等QueueBackgroundWorkItemでは実現困難なことが簡単に実現できる点や将来的なスケールアウトの容易さ等、差別化のポイントはいくつもあるように思います。 (一方QueueBackgroundWorkItemはインプロセス前提なのでHttpContext等ASP.NETの実行インスタンスに依存する情報をHangfire よりもよりシンプルに扱うことができる等のメリット?はあかなーと思ったりもします)

次はClientとServerを別プロセスでやってみたいと思います。

*1:もちろん別のプロセスに分離できます。スケールなど考えるとそちらのほうが良いケースは少なくないでしょう

*2:各オブジェクトは初回実行時に勝手に作成されるのでこのタイミングで手動で作成する必要はありません

ASP.NET CoreでEntity Framework Coreを使わずにDBに接続してみる

.NET CoreでDBアクセスといえば、各種紹介記事やドキュメント、チュートリアルでも Entity Framework Core がよく紹介されています。 個人的にはずいぶん小回りも効くようになってすごくよくなってると思いますし、.NET CoreでのDBアクセス周りは、まずはEntity Framework Coreを使うところから始めてよいように思っています。

とはいえ、そこはやはりコンテキスト次第ではあると思うので、後学のために調べてみました。

 

System.Data.SqlClientを使ってみる

では実際に試してみます。 適当にASP.NET CoreのWebアプリケーションを作成しておきます(認証は無しを選んでおきます)。環境はVS2015 Community 以上を想定します。 対処のDBはとりあえず SQL Serverとします。

CoreFxにおける非EFについのてドキュメントがぱっとみで見当たらなかったのですが、『きっとSystem.Data.SqlClientがそのまま存在するに違いない』と思って検索してみると……やはりありました。

www.nuget.org

ということでまずはインストールしておきます。

PM> Install-Package System.Data.SqlClient
  GET https://api.nuget.org/v3/registration1-gz/system.data.sqlclient/index.json
  GET https://www.nuget.org/api/v2/curated-feeds/microsoftdotnet/Packages(Id='System.Data.SqlClient',Version='4.1.0')
  OK https://www.nuget.org/api/v2/curated-feeds/microsoftdotnet/Packages(Id='System.Data.SqlClient',Version='4.1.0') 282ms
  OK https://api.nuget.org/v3/registration1-gz/system.data.sqlclient/index.json 376ms
'nuget.org' からパッケージ 'System.Data.SqlClient 4.1.0' を取得しています。
NuGet パッケージ System.Data.SqlClient.4.1.0 をインストールしています。
'System.Data.SqlClient 4.1.0' が CoreFxDbSample に正常にインストールされました
NuGet の操作の実行に 37.83 ms かかりました
経過した時間: 00:00:02.3787366

f:id:kiyokura:20161022000202p:plain

スクリーンショットにはないですが、ドリルダウンすると、System.Data.Common何かもちゃんと在って、見ていることが分かります。

 

プロバイダがインストールされたので、適当なSQL Serverに接続してみます。読むテーブルは取り合ずこんな感じのシンプルな奴だと思ってください。

CREATE TABLE [dbo].[User] (
  [Id] INT NOT NULL,
  [Name] NVARCHAR (50) NOT NULL,
  [Email] NVARCHAR (255) NOT NULL,
  [BirthDay] DATETIME NOT NULL,
  PRIMARY KEY CLUSTERED ([Id] ASC)
);

データには何か適当にレコードを入れておきました。

 

とりあえずサンプルなのでHomeControllerに直接書いてみます。何の変哲もない、ADO.NETで普通に接続型でDBを読む場合とまったく同じコードだと思います。 接続文字列はVisual Studioのサーバーエクスプローラーで選択してプロパティからコピーしたものをそのまま使っています*1

// HomeController.cs
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Data.SqlClient;
namespace CoreFxDbSample.Controllers
{
  public class HomeController : Controller
  {
    public IActionResult Index()
    {
      ViewBag.Users = new List<string>();
      using (var con = new SqlConnection("<接続文字列>"))
      using (var cmd = new SqlCommand("SELECT Name FROM Users WHERE Id <= @Id", con))
      {
        cmd.Parameters.Add(new SqlParameter()
        {
          ParameterName = "Id",
          Value = 2,
          DbType = System.Data.DbType.Int32
        });

        con.Open();
        using (var dr = cmd.ExecuteReader())
        {
          while (dr.Read())
          {
            ViewBag.Users.Add(dr["Name"].ToString());
          }
        }
      }
      return View();
    }
  }
}

ついでに結果を見るためにHome/Index.cshtmlもばっさり書き換えておきます。

<!-- Home/Index.cshtml -->
@{
  ViewData["Title"] = "Home Page";
}
<h1>DataReader Sample</h1>
<ul>
  @foreach (var item in ViewBag.Users)
  {
  <li>@item</li>
  }
</ul>

実行してみると、普通に表示されます。 f:id:kiyokura:20161021233323p:plain

この例のとおり、DbConennction, DbCommand , DbParameter, DbDataReaderなど、ADO.NETの基本的な仕組みはポーティングされていて、SQL Server用のプロバイダでもちゃんと実装されていることが分かりました。

NetFxのADO.NETを接続型で使う場合と比較して特に違和感が無い…というか全く同じように使えることが期待できますね。

 

NetFxのADO.NETと比較した制限(2016/10/15 現在)

とはいえ、そのまま移植されているわけではなく、現時点(.NET Core 1.0.1)では利用できない機能がいくつかあります。

 

DataSetやDataTableはまだ実装されていない(もうすぐ入りそう)

DataSetやDataTable、DataAdapterなど、ADO.NETの非接続型の機能を提供するクラスは、現時点(.NET Core 1.0.1)では実装されていません(何か依存物のコンパイルを通すためか、DataTableのみ空で実装はされている模様)。

これらはNetFxでももはやレガシーな機能ですし、WinFormやWebFormなどDataSetを前提としたコンポーネントを活用する(これまたレガシーな)機能は.NET Coreで実装される予定が(今のところ)なさそうなので、このまま実装されずに終わるかな……と思っていたのですが、なんと、ごく最近になってcorefxのmasterにマージされました*2

ということで、近い将来のリリースあたりで入ってくるんじゃないかと思います。

 

 

DataTableに依存した機能は使えない(2016/10/15 現在)

DataTable自体を欲していなくても、DataTableが無いと利用できない機能というのがいくつかあります。私が思いついたのは以下です。 (ただし前述のとおりDataTableが実装されてくれば、将来的にはこれらもちゃんと機能するようになることが期待できそうです。)

Table Value Parameter (テーブル値パラメータ/TVP)

SQL Serverの便利な機能であるTable Value Parameterを.NETのコードから利用する場合、DataTableに格納して渡すことになります。しかし、.NET Core 1.0.1ではDataTableが実装されていないので利用することができません。

SqlConnection.GetSchema

接続先のスキーマ情報を取得するメソッドですが、この戻り値がDataTableだるため、現在は利用できません(GetSchemaが実装されていない)。

 

まとめ

.NET Core 1.0.1の現時点でもDbConnection, DbCommand, DbDataReaderなどの基本的なものは実装されていて、NetFxのADO.NETで利用するのと違和感なく利用できるようです。 現時点のリリースではDataSetやDataTableがまだ実装されていませんが、近い将来のリリースでは含まれてきそうです。

*1:SQL Server認証の場合はパスワードが*になるので書き換える必要があります

*2:これらレガシーな機能がまるっと実装された(だだしTableAdapter はなさそう)理由はよくわかりません。ただ後述のとおりDataTableに依存した機能がいくつかあって、そのためDataTableの実装を望む声は上がっていたようですので、そのあたりも関係しているかもしれません。DataSetについてはどうなんよと思うのですが、ちょっとDataTableのソースを眺めてみた感じではそのなかでもDataSetに依存したコードもあるように見えたので、そう簡単に切り離せるものでは無いのかもしれません。

ASP.NET WebHook (Preview)を試してみた

本エントリはASP.NET Advent Calendar 2015の1日目のエントリです。 今年はなぜかASP.NET Advent Calendar 2015を立てることになったので(とはいえ言い出しっぺではありません)、とりあえず1日目を担当させていただきます。

 

ASP.NET WebHooks

少し前のことですが、ASP.NET の新しいフレームワーク?として、ASP.NET Web Hooks (Preview)というのが登場しました。 f:id:kiyokura:20151130235836p:plain

 

アナウンスのエントリはこちら:
Introducing Microsoft ASP.NET WebHooks Preview

 

Webフック(WebHooks)とは?

WebHooks(Webフック)とはWebサービス同士を連携させるパターンというか方式というか……などど僕が説明するまでもなく、githubやSlackなど、開発者が利用するサービスではをはじめ色々なwebサービスで利用されているものですね。

参考:Webhook - Wikipedia, the free encyclopedia

 

そういえば、去年のASP.NET Advent CalendarでVS Online(現Visual Studio Team Services)のService Hookを受け取るサンプルを作ったエントリ書きましたが、まさにこれですね。

ASP.NET MVC と Azure Web Sites で VS Online のカスタムService Hookを作成してサクッとリモートデバッグする - きよくらの備忘録

 

ASP.NET WebHooksとは

詳細は上記のアナウンスのエントリや、少し前にいさみさんが翻訳されたInfoQの記事などを読んでいただくのが良いと思いますが、ざっくりいえば、

  • (いろんなWebサービスの)Webフックによる通知を受信する機能をサクっと実装する
  • 自分でWebフックを発行する機能をサクっと実装する

ためのインフラを提供するライブラリというかフレームワーク…ととらえて貰えれば良いように思います。

現時点では、 ASP.NET Web API 2 と ASP.NET MVC 5、つまるところ.NET Framework 4.xがターゲットになっているようです。

 

Receiverによるサービス対応

受信側の機能はサービスごとにReceiverを作成することで、プラガブルかつ再利用可能な形でいろいろなサービスに対応できる構造になっています。 現時点でも以下のReceiverが実装・NuGet経由で提供されています。

  • for Azure WebHooks
  • for BitBucket
  • for Dropbox
  • for Github
  • for MailChimp
  • for Paypal
  • for Pusher
  • for Salesforce
  • for Slack
  • for Stripe
  • for Trello
  • for Wordpress
  • for your custom WebHooks implementation
  • for generic WebHooks with special validation logic or security requirements

Visual Studio Onlineに対応したWeb Hooksが無い当たりどうよ、とは思いますがまあ言わないでおきます*1。 もちろん上記のようなドンピシャのReceiverが存在しないサービスであっても、RESTなWeb Hooksのサービスであれば最後の二つのパッケージを利用して(一からやるよりは)楽して実装できそうですし、オリジナルのReceiverを実装することも可能です。

また、Visual Studio 2015向けのExtension、ASP.NET WebHooks Connected Serviceもリリースされています。 このExtensionを利用すると、受信したいサービスを選択するだけで必要なReceiverのパッケージを取り込むなどの下準備を整えてくれます(後ほど実際に試してみます)。

 

もちろんOSS

ASP.NET Web HooksはもちろんOSSで、github上のリポジトリはこちら。 aspnet/WebHooks

Receiverのソースも含まれているので、独自にReceiverを実装する場合も参考にすればよさそうです。

 

リソース

オフィシャルなリソースを以下に整理しておきます。チュートリアル的な記事もあるので軽く目を通して手を動かすのもよさそうです。

 

試してみる(Slack連携)

ではさっそく、少し試してみます。 公式のエントリにもありますが、まずはSlackでサクっとやってみます。

*1:言ってる

続きを読む

OSC 2015 HiroshimaでASP.NET 5とかについてお話させていただきました

9/19(土) オープンソースカンファレンス 2015 Hiroshimaにて「オープンソース&クロスプラットホームとなったASP.NET 5」というタイトルでお話させていただきました。資料はこちら。

ASP.NET 5についてというよりも、マイクロソフトの.NET Framewrok回りのOSS&クロスプラットフォームまわりの状況というか雑感というか、そういうあたりが中心になっている点はご容赦ください。

ASP.NET 5は現在betaでまだまだ破壊的変更も入りそうな気配です。実際にモノを作り始めるならRCを待った方が良いとは思いつつも、気になる点に対してissueを投げたりすることで、ASP.NET自体の開発に参加することも可能だと思います。そういう視点でガンガン触っていくはアリだと思います(ぉ

ASP.NET 5のロードマップが発表されてました

Visual Studio 2015 RTM

昨晩、Visual Studio 2015 が RTMし、MSDNから順次ダウンロード開始されました。合わせてリリース記念イベントなども開催されました。このあたりをひっくるめた詳しい話は、ブチザッキ参照のこと。

Visual Studio 2015 RTM & リリース記念イベント | ブチザッキ

 

How about ASP.NET 5 in Visual Studio 2015 RTM

VS2015世代(?)のASP.NET環境はどうなっているのかというと……*1

ASP.NET 4.6はRTMして、Visual Studio 2015に同梱されて提供されました。

ただし、ASP.NET 5は、少し前から言われていた通り*2現時点ではRTMしておらず、VS2015に同梱されているのはBeta 5というバージョンになります。ベータなのでもちろんですがプロダクション環境でのサポートなどは提供されません。

このあたりのVS2015 RTMでのASP.NET周りの対応状況については、.NET Web Development and Tools Blog の下記のエントリに詳細が書かれています。

Announcing ASP.NET 4.6 and ASP.NET 5 beta 5 in Visual Studio 2015 Release

 

Schedule and Roadmap of ASP.NET 5

さて、本エントリの本題ですが、ASP.NET 5のロードマップがgithub上のwikiで公開されていました。

ASP.NET 5 Schedule and Roadmap

【注意:以下は特に断りがない限り、2015/07/21時点の情報です。最新は上記Wikiなどを確認してください】

かいつまむと、以下の予定だそうです。

マイルストーン リリース予定日
Beta6 2015年07月27日
Beta7 2015年08月24日
Beta8 2015年09月21日
RC1 2015年11月
RCx (フィードバックにより必要に応じて)
1.0.0(RTM 2016年第一四半期(1月~3月)

 

基本的にはBeta 8までの間に機能の実装や未解決の問題の対処を行い、RCでフィードバックを受けながら完成度を高める、という工程になるようです。それぞれのマイルストーンのざっくりした対応内容も上記Roadmapに書かれているので、気になる方はチェックしてみてください。

 

特に注意しておきたいのは、以下のフィーチャーは1.0 RTMの段階では対応されない予定ということです。

これらは1.0では対応を見送られ、2016年のQ3(~9月)までの間に行う予定のリリースでの対応を予定しているようです(あくまで現時点では)。 これらをRTMから外すのはそれなりに大きな決断だったんじゃないかと想像します。 個人的にWeb Pagesがらみの仕様の話が全然表に出てきてなかったのでヤキモキしていたのですが、こういう予定ということで納得しつつも、早く筋道が付いてくれるといいなーと思う今日この頃です。

 

 

*1:まあ上記のブチザッキを見ていただくと書かれているのですが

*2:たとえばSomasegaがblogのコメントに変身する形で公にしています : http://blogs.msdn.com/b/somasegar/archive/2015/06/29/save-the-date-visual-studio-2015-rtm-on-july-20th.aspx#10624584