なか日記

一度きりの人生、楽しく生きよう。

Microsoft Azure WebJobを使って前日の PV をツイートするコードを書いてみた

この前、しばやんが以下のブログを書いてるのを見て、「よし、自分もやってみよう」と思ってからはや4日。一通り形になった(気がしただけだった…)のでブログに書き残しておきます。

準備

まずはVisual Studio 2013 Update3を適用しましょう。

その他にGoogle Analytics APIやTwitter APIの設定が必要ですが、その辺のことはしばやんのブログを見てもらったらいいと思います。

Microsoft Azure WebJobプロジェクトの作成

Visual Studio 2013 Update3から作成できるようになったMicrosoft Azure WebJobテンプレートを使ってプロジェクトを作成します。

f:id:nakaji999:20140807234510p:plain

必要なパッケージのインストール

NuGetで以下のパッケージをインストールしておきます。

上記リンクを見るのが面倒な人はパッケージマネージャコンソールで以下のコマンドを実行して下さい。

PM> Install-Package Google.Apis.Analytics.v3
PM> Install-Package CoreTweet

コード

面倒なのでstaticおじさんな感じでべたっと書きます。Google Analytics API周りははっきり言ってしばやんの丸パクリです。

using System;
using System.Configuration;
using System.Security.Cryptography.X509Certificates;
using CoreTweet;
using Google.Apis.Analytics.v3;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;

namespace TweetPV_WebJob
{
    // To learn more about Microsoft Azure WebJobs, please see http://go.microsoft.com/fwlink/?LinkID=401557
    class Program
    {
        static void Main()
        {
            try
            {
                var analyticsKeyFile = GetSettings("analyticsKeyFile");
                var certificate = new X509Certificate2(analyticsKeyFile, "notasecret", X509KeyStorageFlags.Exportable);

                // Scopes は指定しないとエラーになる
                var analyticsCredentialId = GetSettings("analyticsCredentialId");
                var credential =
                    new ServiceAccountCredential(new ServiceAccountCredential.Initializer(analyticsCredentialId)
                    {
                        Scopes = new[] { AnalyticsService.Scope.Analytics, AnalyticsService.Scope.AnalyticsReadonly }
                    }.FromCertificate(certificate));

                // HttpClientInitializer に credential 入れるのは違和感あるけど正しいらしい
                var service = new AnalyticsService(new BaseClientService.Initializer
                {
                    HttpClientInitializer = credential,
                    ApplicationName = "TweetPV",
                });

                // Azure は UTC なので +9 時間して -1 日
                var date = DateTime.UtcNow.AddHours(9).AddDays(-1).ToString("yyyy-MM-dd");

                // ****** はメモしたビューの ID
                var analyticsViewId = GetSettings("analyticsViewId");
                var task = service.Data.Ga.Get("ga:" + analyticsViewId, date, date, "ga:pageviews").ExecuteAsync();
                task.Wait();

                var pv = int.Parse(task.Result.Rows[0][0]);
                var message = string.Format("昨日のなか日記のPVは {0} でした", pv);

                var consumerKey = GetSettings("consumerKey");
                var consumerSecret = GetSettings("consumerSecret");
                var accessToken = GetSettings("accessToken");
                var accessSecret = GetSettings("accessSecret");

                var token = Tokens.Create(consumerKey, consumerSecret, accessToken, accessSecret);
                token.Statuses.UpdateAsync(status => message).Wait();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
            }
        }

        public static string GetSettings(string key)
        {
            var value = Environment.GetEnvironmentVariable(key);
            try
            {
                if (!string.IsNullOrWhiteSpace(value)) return value;

                value = ConfigurationManager.AppSettings[key];
                return value;
            }
            finally
            {
                Console.WriteLine("{0}:{1}", key, value);
            }
        }
    }
}

Azure WebJobプロジェクトはローカル環境ではコンソールアプリケーションとして実行できます。コンソールアプリケーションと何が違うの?と言われると、正直違いはないと思います。Azure WebJobとして発行できるかどうかの違いじゃないでしょうか。

ちなみに、アクセストークン等の設定は先日書いたブログ+αの処置をしてます。

configファイルから設定読み込むだけで良いはずなのに何で環境変数まで見ているのかは、この後で説明します。

App.configはこんな感じ。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings file="D:\Visual Studio 2013\秘密の設定\TweetPV_WebJob\local.config">
    <add key="analyticsKeyFile" value="key.p12" />
    <add key="analyticsCredentialId" value="*****@developer.gserviceaccount.com" />
    <add key="analyticsViewId" value="99999999" />

    <add key="consumerKey" value="*****" />
    <add key="consumerSecret" value="*****" />
    <add key="accessToken" value="*****" />
    <add key="accessSecret" value="*****" />
  </appSettings>
 ~略~
</configuration>

Azureに発行する

そして、Azureにデプロイするわけですが、Webサイトの作成からWebJobの設定まで全てVisual Studioでできちゃいます。

ソリューションエクスプローラのプロジェクトを右クリックして「Azure WebJobとして発行する」を実行します。

f:id:nakaji999:20140808001901p:plain

するとウィザードが起動して、発行するWebサイトの指定(新規作成も可)やWebJobの設定ができるようになります。

f:id:nakaji999:20140807234435p:plain

ちょっとした問題

アクセストークン等の秘密の設定についてちょっと悩みました。Webサイトの場合はアプリケーション設定で上書きすればいいよねーという事を書きましたが、WebJobはWebサイト上で動くexeなんですよね。なので、ConfigurationManagerのAppSettingsではアプリケーション設定に書いた値を取ってくることができません。

そこで、Visual Studio Onlineのコンソールで遊んでいるとアプリケーション設定に書いた内容が環境変数に反映されているのを発見。

f:id:nakaji999:20140808005637p:plain

そこで先ほどのソースに戻りますが、Azure上では環境変数に設定されている値を使用して、ローカルではApp.configの値を使用する様な小細工をしたわけです。

ここまで書いて気がついた

スケジュール実行する場合には「WebJobs-[リージョン]」という名前でスケジューラが作成される様なのですが、西日本リージョンでは動いてないようです。

f:id:nakaji999:20140808010623p:plain

スケジューラ単体で作成(スクリーンショットでは「TweetPV」)した場合は動いているみたいなので、西日本はWebJobsに対応してないのかなぁ。

と思って、米国西部にデプロイしてみたけど同じだった…にわかにはこれ以上難しいので、えらい人に教えてもらおうと思います。

2014/08/10 追記

Microsoft Azure WebJobのスケジューラの件 - なか日記に書きましたが、スケジューラちゃんと動きました。原因はよくわからないのですが…