diary

I like Hatena Star with a text selection.

2020-01-19

デッドロックしたりしなかったりするコードができた。

q = Queue.new

Thread.new do
  q.pop.run
end

t = Thread.new { Thread.stop }
q << t
t.join

p 'finish'

pushしたthreadがpopされる前に t.join が実行されると、一時的に全部のスレッドがsleepした状態になるのかなあ。

Thread.stopq.pop.runの後に呼ばれてしまうと、すべてのスレッドが停止してしまう。 tompngさんに指摘してもらった。

t = Thread.new { Thread.pass; Thread.stop }みたいに書き換えると必ず?deadlockするようになってわかりやすかった。


元同僚に"中公新書の『物語 {国名}の歴史』"シリーズをおすすめしてもらった。次に読む本として積んでおきたい


graphql-clientを使ってGitHub API v4を叩く際、スキーマをHTTP越しにロードするのにも認証が必要でちょっと不便。 普通はcontextを使ってaccess tokenを渡すと思うのだけど、READMEにあるGraphQL::Client.load_schemaを使うとcontextを渡せないのでうまく行かない。

def v4_client(github_access_token)
  http = GraphQL::Client::HTTP.new('https://api.github.com/graphql') do
    def headers(context)
      {
        "Authorization" => "Bearer #{context[:github_access_token]}"
      }
    end
  end

  schema = GraphQL::Client.dump_schema(http, context: { github_access_token: github_access_token })
  GraphQL::Client.new(schema: schema, execute: http)
end

そのため、上のコードのようにGraphQL::Client.dump_schemaを使ってcontextを渡してSchemaをHTTP越しに持ってこないといけない。

この辺でエラーが起きた時にその原因が本当に分かりづらくて、コードを読まないと絶対に理解不能だと思う。 graphql-client gemはここしかコードを読んでないけど、ここだけ読むと本当に酷くて「これ使って平気なやつかな?」という気分になる。

https://github.com/github/graphql-client/blob/6488e4c0f4f2a1d32a77ceb6180bf185a82e8ca6/lib/graphql/client.rb#L47-L68

……などと言っていたのだけど、結局この方法は厳しそうということが分かった。 なぜならば"定数にアサインされなければならない"クエリを定義するには上で作成したクライアントが必要であるため。

なので、さらに小細工をしないと(例えば動的に定数をアサインする!)この手法は無理っぽい。 流石にそこまでしてこの方法にこだわりたくはない。

解決策としてはいくつか考えられる。

  • schema.jsonを事前に取得しておいて、それをファイル経由でload_schemaする
    • 取得する時にさえトークンを指定しておけば良い
  • 諦めて環境変数トークンを持つ
    • requireするだけでHTTPリクエストが走ることになる
  • https://developer.github.com/v4/public_schema/ からスキーマをダウンロードする
    • これは認証がいらなくて便利
    • しかしこれはJSON形式ではないため、load_schemaメソッドからは読めない。
    • GraphQL.parse(content)すると読めるので、これを使えるんじゃないかなあ(未確認)

とまあこんな感じで大変そうなので、素直にnet/httpとかで雑にAPIを叩いたほうが楽そう。 gemの依存も少なくて済むし、graphql-rubyが吐く警告の川も見なくて済むし、謎のハックもいらないし、net/httpのほうがよっぽど良いなあ……

結局 https://gist.github.com/pocke/27155765598bc912059f5b629f25664d を元に雑なクライアントを書いた。 https://github.com/pocke/slahub/blob/2aa2145124719758f754629f893ddbecd19620a8/lib/slahub/github_client/v4.rb


ruby-jpのSlackでpaizaについての感想を書いたので日記に転記しておく。

ざっと眺めた感想です

  • D問題: プログラミング自体や言語の入門としては良さそう。ここで苦戦していたら、簡単な問題をコードに落とし込むのにつまづいていそう。Rubyだと3行ぐらいで解ける問題が多そう。
  • C問題、B問題: まだ計算量とかを考えなくても良いけど、少し複雑になってそう。問題を解いているうちにRubyのいろんな組み込みライブラリに詳しくなれそう。
  • A問題: 計算量の概念とかよく出るアルゴリズムを知っていると解けそう?
  • S問題: 解いてなかったから分からん

B問題ぐらいまでは、「こういう処理をしたい時にこう書ける」みたいな経験を積むのに役立つかなあと思います。A問題当たりからはhanachinさんが言ってる「計算量の概念とかアルゴリズム」を気にしていく必要があって、このへんは実務でもじんわり効いてくるところかなあと思います

C、B問題あたりはC言語とかで解いてたらもう少し真面目にデータ構造を意識したりアルゴリズムを考えたりする必要があるのかなあと思いますが、Rubyで解いているとその代わりにArrayやStringの便利メソッドに詳しくなりがち