元祖赤のれん 節ちゃんラーメン 天神本店

先日は並んでいて断念した『元祖赤のれん 節ちゃんラーメン 天神本店』にリベンジ。今回はすぐに席に着けたけど、直後に満席だったから間一髪だったな。移転後初入店。

ラーメンと半チャーハンの A セット(680円)を注文。ここは麺が柔らかいので、柔らかい麺が好みじゃない人は最低でも硬めを頼んだ方がいい。自分はもちろん硬めで。

福岡のラーメンでは今は珍しい平麺と、醤油とんこつのスープは、どこか懐かしい味。

半チャーハンは程よくパラパラで、程よくしっとり。これまた昔の中華料理屋のチャーハンって感じで良い。

ラーメンと半チャーハンで 680 円というのは、コストパフォーマンスが非常に高い。サラリーマンがお昼にラーメンを食べるときの選択肢としてかなり有力。680 円て、他のラーメン屋だとラーメン一杯の値段だし。このままお財布に優しい店であってほしい。

『服を着るならこんなふうに(6)』を読んだ

6巻のテーマは脱ノームコア。ベーシックなコーディネートは安定感あるけど、地味になりがちなので、いつかは通る道なんだろうな。自分もそろそろか。

表情のある素材を使う場合はコーディネートの中で一つだけ、柄物を使う時もコーディネートで一つだけ、という教えは勉強になった。こういう、はっきりとした分かりやすい目安を載せてくれるのが、この漫画の良いところだな。

『王様達のヴァイキング(14)』を読んだ

ラスボスが登場して、いよいよ最終決戦かと思っていたけど、まだ続くみたい。 ラスボスが日本のトップになるとはね。まさに魔王だな。

勇者是枝御一行は、かつての宿敵をパーティに加え、魔王の懐に潜り込んで討伐の機会をうかがうわけだが、そこで開発するサイバー防衛システムは、自分には非現実的過ぎるな。犯罪者を識別する顔認識は機械学習だと思うけど、通信を傍受する方は専門外なので、ちょっと実現方法が思いつかない。

ラスボスが登場したあたりから、作中に登場するテクノロジーが現実を超えてきた気がする。 もう SF。 今までリアルに感じていただけに、高度に発達したテクノロジーは魔法と区別つかない、というのを擬似体験した気分だ。

王様達のヴァイキング(14) (ビッグコミックス)

王様達のヴァイキング(14) (ビッグコミックス)

一心不乱

赤のれんに行ったら結構並んでいて、待っていたら昼休みが終わりそうだったので、予定変更。すぐ近くにある『一心不乱』に入った。

食べたのは『黒のコクとんこつラーメン』とご飯と餃子のセット。久しぶりに食べる濃厚とんこつは、スープに確かなコクがあって旨し。自分の中のとんこつランキングで結構良い線いってる。

餃子はニンニクが効いていて、これまたイケル。 3個じゃ食べ足りなかったけど、 ご飯は追加料金なしで大盛りにしてもらえたので、満足度は高い。

『みんなの Go 言語』を読んだ

少しずつ読み進めて、ようやく読了。技術書なのに雑誌っぽい紙面で、まるで WEB+DB PRESS を読んでいるみたいだった。

中身は実際にアプリケーションを開発するときに使える TIPS で溢れていて、チュートリアルと本書を読めば Go 言語入門はひとまず終了してよさそう。あとは実践あるのみ。

みんなのGo言語【現場で使える実践テクニック】

みんなのGo言語【現場で使える実践テクニック】

Azure Functions を使った Azure Storage の増分バックアップ

先日作成した Azure Storage のコンテナをバックアップするプログラムは、高速化しても完了までに 5 時間弱かかる。

tnakamura.hatenablog.com

こいつを毎日実行するのは気が引ける。コンテナの完全バックアップは週一回にしておき、増分バックアップを毎日取る方針に切り替えた。

最初、増分バックアップも完全バックアップ同様にコンソールアプリケーションで作成し、夜間に実行しようと思ったけど、ふと閃いた。Azure Functions を使えば良いのでは、と。Azure Functions はブロブが登録されたのをトリガーに起動できるから、都度コピーすれば増分バックアップの出来上がりってことになる。

早速 Azure Functions を書いてみた。ソースコードを Git で管理したかったので、Visual Studio で Azure Functions プロジェクトを作成している。コードは次の通り。

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;

namespace AzureStorageIncrementalBackup
{
    // Azure Functions を使って増分バックアップ
    public static class AzureStorageIncrementalBackup
    {
        // ブロブが登録されると起動する
        [FunctionName("AzureStorageIncrementalBackup")]
        public static void Run([BlobTrigger("mycontainer/{name}", Connection = "AzureWebJobsStorage")]CloudBlockBlob myBlob, TraceWriter log)
        {
            CopyBlobAsync(myBlob, log).GetAwaiter().GetResult();
        }

        // 日本標準時の現在時間を取得する
        static DateTimeOffset JstNow => DateTimeOffset.UtcNow.ToOffset(TimeSpan.FromHours(9));

        // ブロブをバックアップ用のストレージアカウントにコピーする
        static async Task CopyBlobAsync(CloudBlockBlob myBlob, TraceWriter log)
        {
            var destConnectionString = "<コピー先のストレージアカウントの接続文字列>";
            var destStorageAccount = CloudStorageAccount.Parse(destConnectionString);
            var destBlobClient = destStorageAccount.CreateCloudBlobClient();

            // 今日の日付のコンテナが無ければ作る
            var destContainerName = $"mycontainer-incremental-{JstNow.ToString("yyyyMMdd")}";
            var destContainer = destBlobClient.GetContainerReference(destContainerName);
            try
            {
                await destContainer.CreateIfNotExistsAsync();
            }
            catch (Exception e)
            {
                log.Error(e.Message);
            }

            try
            {
                var destBlockBlob = destContainer.GetBlockBlobReference(myBlob.Name);
                log.Info($"{destBlockBlob.Name} にバックアップします。");

                using (var stream = await myBlob.OpenReadAsync())
                {
                    await destBlockBlob.UploadFromStreamAsync(stream);
                }

                log.Info("バックアップ成功");

            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
                log.Info("バックアップ失敗");
            }
            finally
            {
                log.Info("バックアップ完了");
            }
        }
    }
}

Microsoft Azure ポータルから Function App を作成し、Visual Studio から発行すればデプロイ完了。今回の要件は Azure Functions にピッタリだった。

WCF on .NET Core

.NET Core でも WCF を使うことはできる。提供されているのはクライアントライブラリだけなので、.NET Core で動く WCF サービスを作ることはできないけど。

試しに TCP でやってみた。WCF サービスは .NET Framework で作るしかない。

using System;
using System.Runtime.Serialization;
using System.ServiceModel;

namespace DotNetFrameworkWcf
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = ".NET Framework WCF";

            var host = new ServiceHost(typeof(BookService));
            host.AddServiceEndpoint(
                typeof(IBookService),
                new NetTcpBinding(),
                "net.tcp://localhost:8080/BookService");
            host.Open();

            Console.WriteLine("Enter で終了");
            Console.ReadLine();

            host.Close();
        }
    }

    [DataContract]
    public class Book
    {
        [DataMember]
        public string Author { get; set; }

        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public decimal Price { get; set; }
    }

    [ServiceContract]
    public interface IBookService
    {
        [OperationContract]
        Book Echo(Book book);
    }

    public class BookService : IBookService
    {
        public Book Echo(Book book)
        {
            Console.WriteLine($"{book.Author} - {book.Title} \\{book.Price}");
            return book;
        }
    }
}

.NET Core のコンソールアプリケーションを新規作成し、System.ServiceModel.NetTcp パッケージを追加。

www.nuget.org

WCF サービスを呼び出してみる。ChannelFactory の使い方がちょっと違うけど、悩むほどではない。

using System;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace DotNetCoreWcf
{
    using DotNetFrameworkWcf;

    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = ".NET Core WCF";

            var factory = new ChannelFactory<IBookService>(
                new NetTcpBinding(),
                new EndpointAddress("net.tcp://localhost:8080/BookService"));
            var channel = factory.CreateChannel();

            var result = channel.Echo(new Book()
            {
                Author = "赤坂アカ",
                Title = "かぐや様は告らせたい 7",
                Price = 500,
            });
            Console.WriteLine($"{result.Author} - {result.Title} \\{result.Price}");

            Console.WriteLine("Enter で終了");
            Console.ReadLine();

            ((IChannel)channel).Close();
        }
    }
}

namespace DotNetFrameworkWcf
{
    [DataContract]
    public class Book
    {
        [DataMember]
        public string Author { get; set; }

        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public decimal Price { get; set; }
    }

    [ServiceContract]
    public interface IBookService
    {
        [OperationContract]
        Book Echo(Book book);
    }
}

先にサービスを起動しておいて、クライアントを実行。

f:id:griefworker:20171124173150p:plain

.NET Framework で作った WCF サービスを、.NET Core から問題なく呼び出せた。.NET Core で WCF サービスは需要無いだろうから、今後もパッケージが提供されることはないんだろうな。

実際、自分も必要としているのはクライアント側だけで、.NET Core で WCF サービスを作りたいとは思わない。.NET Core で動かしている ASP.NET Core アプリケーションから、レガシーな WCF サービスを呼び出せれば十分。