LoginSignup
2
0

More than 1 year has passed since last update.

SinatraでCtrl+Cを2回押さないと停止しない問題

Last updated at Posted at 2022-07-05

事の始まり

( ^o^)「Sinatraでメモアプリ作るぞ〜〜」

( ^o^)「起動を確認して…大丈夫だな。Ctrl+Cで終了するぞ」

(; ^o^)「…あれ!?一回押しただけじゃ終わらない!?」

結論(原因)

  • スーパークラスの指定を間違えていた
  • READMEをしっかり読んでいなかった
    • 思い込みでコードを書いていた
  • GitHub(ソースコードやissue、使用例)を読んでいなかった
  • 開発のためにrequireしていたものが影響を与えていた

開発環境

Ruby 3.1.2p20
Sinatra 2.2.0

Sinatraとは?

Sinatra is a DSL for quickly creating web applications in Ruby with minimal effort:
引用元: Sinatra

簡単にRubyでWebアプリケーションを作ることができるDSLだそうです。
使用してみた感じは、「Railsより簡単に扱える」「シンプルなWebアプリケーションを作るのに向いている」という感触でした。
READMEの日本語版が用意されているので「英語わからん」って人でもすぐに触ることができます!

今回の問題点

タイトルにもあるとおり、Sinatraを終了させるのにCtrl+Cを一回押しても終わらない(2回押したら終了する。)という状態でした。

ログと画面

bundle exec ruby app.rbでSinatraを起動してから終了するまでのログとスクリーンショットを貼ります。
いずれも localhost:4567 です。

起動直後

正常にアプリが起動します。

$ bundle exec ruby app.rb
[2022-07-04 15:32:57] INFO  WEBrick 1.7.0
[2022-07-04 15:32:57] INFO  ruby 3.1.2 (2022-04-12) [arm64-darwin21]
== Sinatra (v2.2.0) has taken the stage on 4567 for development with backup from WEBrick
[2022-07-04 15:32:57] INFO  WEBrick::HTTPServer#start: pid=68679 port=4567
::1 - - [04/Jul/2022:15:32:58 +0900] "GET / HTTP/1.1" 200 3873 0.0281
::1 - - [04/Jul/2022:15:32:58 JST] "GET / HTTP/1.1" 200 3873
- -> /

スクリーンショット 2022-07-04 15.33.22.png

Ctrl + Cを一度押した後

更新するとSinatraのエラー画面が表示されるようになりました。

^C== Sinatra has ended his set (crowd applauds)
[2022-07-04 15:35:49] INFO  going to shutdown ...
[2022-07-04 15:35:49] INFO  WEBrick::HTTPServer#start done.
[2022-07-04 15:35:49] INFO  WEBrick 1.7.0
[2022-07-04 15:35:49] INFO  ruby 3.1.2 (2022-04-12) [arm64-darwin21]
== Sinatra (v2.2.0) has taken the stage on 4567 for development with backup from WEBrick
[2022-07-04 15:35:49] INFO  WEBrick::HTTPServer#start: pid=68679 port=4567

スクリーンショット 2022-07-04 15.36.23.png

Ctrl + Cを二度押した後

ここでやっと終了しました。

^C== Sinatra has ended his set (crowd applauds)
[2022-07-04 15:36:51] INFO  going to shutdown ...
[2022-07-04 15:36:51] INFO  WEBrick::HTTPServer#start done.

スクリーンショット 2022-07-04 15.37.10.png

コード

最初はクラシックスタイルで開発し、途中からRubocopのMixinUsageの指摘を受けないようにするためモジュラースタイルに切り替えました。
モジュラースタイルに切り替えてから今回の問題が発生するようになりました。

クラシックスタイル

app.rb
# frozen_string_literal: true

require 'sinatra'
require 'sinatra/reloader'

include ERB::Util

# 省略

get '/' do
  # 省略
end

モジュラースタイル

app.rb
# frozen_string_literal: true

require 'sinatra'
require 'sinatra/reloader'

class App < Sinatra::Application
  include ERB::Util
  # 省略

  get '/' do
    # 省略
  end

  run! if app_file == $PROGRAM_NAME
end

解決策

Sinatra requires CTRL+C twice to shutdown にて同様の現象が報告されていたため確認をしました。モジュラースタイルで書くときには sinatra ではなく sinatra/baseをrequireするようです。

Sinatra::Base - ミドルウェア、ライブラリおよびモジュラーアプリでもsinatra/baseをrequireしています。しっかり読むべきでした……

ただし、今回はrequire sinatra/baseを変更しただけでは終わりませんでした。

require sinatra/baseに修正してみる

先ほどのapp.rbを修正します。

app.rb
# frozen_string_literal: true

require 'sinatra/base' # 修正
require 'sinatra/reloader'

class App < Sinatra::Application
  include ERB::Util
  # 省略

  get '/' do
    # 省略
  end

  run! if app_file == $PROGRAM_NAME
end

実行すると

$ bundle exec ruby app.rb 

何も起きなくなりました。

sinatar/reloaderを消す

他に原因があるとするならばreloaderかもと思いコメントアウトしてみました。

app.rb
# frozen_string_literal: true

require 'sinatra/base' # 修正
# require 'sinatra/reloader'

class App < Sinatra::Application
  include ERB::Util
  # 省略

  get '/' do
    # 省略
  end

  run! if app_file == $PROGRAM_NAME
end

実行!

$ bundle exec ruby app.rb
[2022-07-05 11:55:35] INFO  WEBrick 1.7.0
[2022-07-05 11:55:35] INFO  ruby 3.1.2 (2022-04-12) [arm64-darwin21]
== Sinatra (v2.2.0) has taken the stage on 4567 for development with backup from WEBrick
[2022-07-05 11:55:35] INFO  WEBrick::HTTPServer#start: pid=4566 port=4567

動く!!

^C== Sinatra has ended his set (crowd applauds)
[2022-07-05 11:57:54] INFO  going to shutdown ...
[2022-07-05 11:57:54] INFO  WEBrick::HTTPServer#start done.

Ctrl+C一回で停止する!!!

理由はわからず…

Sinatra::Base白紙の状態です。組み込みサーバーを含め、ほとんどのオプションはデフォルトで無効になっています。使用可能なオプションとその動作の詳細については、設定の構成を参照してください。アプリをトップレベルで定義する場合(クラシックスタイルとも呼ばれます)に似た動作が必要な場合は、次のようにサブクラス化できますSinatra::Application。
引用元: README

GitHubを確認してみる

Sinatra::Applicaton

Execution context for classic style (top-level) applications. All DSL methods executed on main are delegated to this class.
The Application class should not be subclassed, unless you want to inherit all settings, routes, handlers, and error pages from the top-level. Subclassing Sinatra::Base is highly recommended for modular applications.

Google先生に翻訳してもらいました。

クラシックスタイル(トップレベル)アプリケーションの実行コンテキスト。 mainで実行されるすべてのDSLメソッドは、このクラスに委任されます。
トップレベルからすべての設定、ルート、ハンドラー、およびエラーページを継承する場合を除いて、Applicationクラスをサブクラス化しないでください。 Sinatra :: Baseのサブクラス化は、モジュラーアプリケーションに強くお勧めします。

READMESinatra::Applicationをサブクラス化する方法も紹介してるから、絶対にBaseを継承する必要はなさそう:thinking:

reloader

使用例のモジュラースタイルでは Sinatra::Baseを継承してて、Sinatra::Applicationを継承する例は見つからず…。モジュラースタイルでSinatra::Applicationを継承する場合は使わない方が良いのだろうか:thinking:

最後に

今回の事象は一人で解決できませんでした。現在参加してるFjordBootCampで質問をして、メンターのShohei Umemotoさんに「GitHubのissueを確認してみよう!」とアドバイスをいただいた結果解決につながりました。
今回に限りませんが、自分のわからない!って状態を外に発信するのは非常に大事だなと感じます:smile:

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0