【Android】ビーコン受信時のクラッシュ対応

エラー内容

1
org.altbeacon.beacon.service.RangedBeacon.addMeasurement (RangedBeacon.java:79)

解決策

app/proguard-project.txtに以下を追加する

1
-keep class org.altbeacon.beacon.service.** { *; }

参考

https://github.com/AltBeacon/android-beacon-library/issues/1164

その他

debugモードでビルドした時は再現できないので注意
releaseモードでビルドした時に再現する

RubyMineでデバッグするための設定

はじめに

RubyMineでデバッグ実行しようとしたら色々とハマりまくって半日潰れて悔しかったので、完全体となった今の設定をメモしておきます。

gemのinstallはRubyMineでアプリ実行時に自動的に行われるので、自分でbundle installする必要はありません。
必要はないというか、やるとエラーになります。。

環境

  • Rubyのバージョン
1
2
ruby --version
ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c5) [x86_64-darwin22]
  • RubyMineのバージョン
1
RubyMine 2023.2.6

※最新版だとうまく動かなかった。このバージョンまで落としたらうまく動きました。。

  • docker-compose.yml
1
2
3
4
5
6
7
8
9
10
web:
command: bash -c 'rm -f tmp/pids/server.pid && bundle install --jobs=4 --retry=3 && yarn install && ./bin/rails i18n:js:export && ./bin/dev'
ports:
- "1234:1234" # for debug
- "3000:3000"
- "33333:33333" # for selenium-grid
- "26162:26162" # for debug
- "26166:26168"
- "3036:3036" # vite
- "3037:3037" # vite
  • Gemfile
1
2
3
gem 'ruby-debug-ide'
gem 'debase', '~> 0.2.5.beta2', require: false
gem "debug", ">= 1.0.0", require: false
  • RubyMineのDockerComposeの設定

※docker-compose(V1の方)になっていたので、dockerに変更しました。

  • RubyMineのRuby SDKの設定

※(2)の方は最初は存在しないと思います。「+」ボタンから作ってください。

エラー一覧

色々エラー出すぎてどのエラーがどの解決策に対応しているのかわからなくなったけど、
とりあえずメモしておきます。

1
2
3
4
An error occurred while installing debase (0.2.5.beta2), and Bundler cannot continue.

In Gemfile:
debase
1
2
3
Attaching to web-1
web-1 | /usr/local/bin/ruby: No such file or directory -- /opt/.rubymine_gems/gems/ruby-debug-ide-3.0.0.beta.17/bin/rdebug-ide (LoadError)
Aborting on container exit...
1
Caused by: java.io.IOException: Cannot run program "/usr/local/bin/docker-compose" (in directory "/Users/ryosuke/Public/20221219_zaico_web/zaico_web"): error=2, No such file or directory
1
Docker ボリューム 'Rubymine_2024_internal_gems_storage_4a5bbe64_dockercomposeUsersryosukePubli' をセットアップできませんでした。

「session deleted because of page crash」エラーの解決方法

Rspecでテストを実行すると、以下のエラーが発生しました。

1
2
3
4
RSpec::Core::MultipleExceptionError: unknown error: session deleted because of page crash
from unknown error: cannot determine loading status
from tab crashed
(Session info: headless chrome=117.0.5938.62)

解決策

Chromeブラウザを最新化すると解決しました。

【RubyMine】「SDKにRailsが見つかりません」エラーの解決方法

解決策

SDKを追加する(そのままですね)

  • RubyMine>設定>言語 &フレームワーク>zaico_webで「+」ボタンを押す

【読書メモ】Webパフォーマンスチューニング

Chapter1 チューニングの基礎知識

  • 推測するな、計測せよ
  • ボトルネックはどこか?CPU?メモリ?
  • ネットワークIO?アプリ処理?データベースIO?など

Chapter2 モニタリング

  • CPUやメモリの監視→モニタリング
  • totalコマンドやfree --humanコマンドでそれぞれの情報を確認できる
  • が、それだとその瞬間の値しか見れない
  • 推移が見たいときは例えば1分ごとに実行し、結果を記録する必要がある
  • 手動じゃ無理
  • なのでツールに頼ろう
  • 有名なのはPrometheus(プロメテウス)
  • これは監視用のサーバーを別途立てて、そこにPrometheusを起動して、監視対象のサーバーに定期的にアクセスして結果を記録するやつ
  • 監視対象先のサーバーにもPrometheusからのアクセスされるためのエンドポイントの用意が必要
  • これはnode_exporterツールを使うと便利
  • Prometheusはモニタリング結果のダッシュボード表示もできるよ
  • ハマりがちな罠:CPUが複数ある場合、瞬間的な増減の見落としなど

Chapter3

  • 負荷試験をやろう
     - abコマンド(Apache Bench)が便利
     - 指定したURLに指定した回数擬似リクエストできる
  • topコマンドで、MySQL・Webアプリ・WebサーバーなどどれがCPUを多く使っているか確認しよう
  • MySQLがボトルネックの場合、遅いSQL(スロークエリ)を特定しよう
     - my.cnfのslow_query_logを1に設定すると表示される
  • 対象のSQLが特定できたらEXPLAINで実行計画を確認しよう
  • 必要に応じてインデックスを貼るなど検討しよう

Chapter4

  • 単一のURLへの負荷試験に加えて、シナリオを持った負荷試験をやろう
  • 例えばログインして、データを登録して、削除して、とか
  • k6というツールで実現できる

Chapter5 データベースのチューニング

  • RDBMSは一貫性があることが強み。データのロックがあるので。
  • 性能重視ならNoSQLもあり。memcachedやRedisなど。
  • インデックスは便利だけど多すぎるとデータの追加・更新の負荷が増えるので注意
  • SQLにEXPLAINをつけて実行計画を確認しよう
  • SQL回数が多すぎるものはN+1問題を疑おう
  • N+1問題の解決策として、キャッシュ、別SQL、JOINなどが有効

Chapter6 リバースプロキシの利用

  • リバースプロキシはクライアントとアプリケーションサーバーの中継役
  • リバースプロキシを置かない場合、大量リクエストが来た場合、通信が遅いクライアントに専有されたりしてしまう
  • せいぜい1万リクエストが上限なのでC10K問題と呼ばれる
  • 代表的なリバースプロキシがnginx
  • gzipの設定などを行うことで高速化できる

Chapter7 キャッシュの活用

  • キャッシュにはアプリケーションで作成するものと、クライアントによるHTTPレスポンス自体のキャッシュがある
  • 本章ではアプリケーションによるキャッシュが対象
  • 代表的なキャッシュアプリはmemcachedとRedis
  • キャッシュをアプリケーションのメモリやファイルに保存する方法もあるが、並列の処理・有効期限・削除などに注意が必要
  • ただ、キャッシュはデータの不整合(古いデータを表示してしまう)など処理が複雑になるデメリットがある
  • キャッシュヒット、キャッシュミスの割合を監視して適切にキャッシュが使えているか監視しよう

Chapter8 押さえておきたい高速化手法

  • 開発用の設定で冗長なログを出力しない
  • 画像データをMySQLではなく静的ファイル配信しよう
  • urlにランダム文字列を付与(app.js?v=ramdom_stringなど)することでキャッシュを利用されないようにできる(キャッシュバスター)
  • HTTPヘッダーを活用してクライアント側にキャッシュさせる
    • cssはjsファイルなどはあまり変更ないのでキャッシュさせたい
    • If-Modified-Sinceヘッダーなどを利用しよう

Chapter9

Android開発でJavaバージョンに関するビルドエラー

ビルドエラーの内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
> Could not resolve all files for configuration ':classpath'.
> Could not resolve com.android.tools.build:gradle:7.4.2.
Required by:
project :
> No matching variant of com.android.tools.build:gradle:7.4.2 was found. The consumer was configured to find a runtime of a library compatible with Java 8, packaged as a jar, and its dependencies declared externally, as well as attribute 'org.gradle.plugin.api-version' with value '7.5' but:
- Variant 'apiElements' capability com.android.tools.build:gradle:7.4.2 declares a library, packaged as a jar, and its dependencies declared externally:
- Incompatible because this component declares an API of a component compatible with Java 11 and the consumer needed a runtime of a component compatible with Java 8
- Other compatible attribute:
- Doesn't say anything about org.gradle.plugin.api-version (required '7.5')
- Variant 'javadocElements' capability com.android.tools.build:gradle:7.4.2 declares a runtime of a component, and its dependencies declared externally:
- Incompatible because this component declares documentation and the consumer needed a library
- Other compatible attributes:
- Doesn't say anything about its target Java version (required compatibility with Java 8)
- Doesn't say anything about its elements (required them packaged as a jar)
- Doesn't say anything about org.gradle.plugin.api-version (required '7.5')
- Variant 'runtimeElements' capability com.android.tools.build:gradle:7.4.2 declares a runtime of a library, packaged as a jar, and its dependencies declared externally:
- Incompatible because this component declares a component compatible with Java 11 and the consumer needed a component compatible with Java 8
- Other compatible attribute:
- Doesn't say anything about org.gradle.plugin.api-version (required '7.5')
- Variant 'sourcesElements' capability com.android.tools.build:gradle:7.4.2 declares a runtime of a component, and its dependencies declared externally:
- Incompatible because this component declares documentation and the consumer needed a library
- Other compatible attributes:
- Doesn't say anything about its target Java version (required compatibility with Java 8)
- Doesn't say anything about its elements (required them packaged as a jar)
- Doesn't say anything about org.gradle.plugin.api-version (required '7.5')

原因

Java のバージョンが合っていない

IDEの設定

Android Studio>Settings>Build,Execution,Deployment>Build Tools>Gradle>Gradle JKDでjava11を設定する
パスをコピーしておく

プロジェクト本体の設定

gradle.propertiesファイルにコピーしたパスを追記する。
例えば以下など

1
/Library/Java/JavaVirtualMachines/openjdk-11.0.1.jdk/Contents/Home

RailsにRedisを導入した際のメモ

redisライブラリの導入

Gemfileに以下を追加する。

1
2
gem 'redis'
gem 'hiredis-client'

Railsのキャッシュの設定

  • Railsのキャッシュのデフォルトの保存先はtmpファイルになっている(キャッシュストアの設定
  • Redisを使うように変更するには以下のようにする

対象ファイル:config.enveronments/production.rb

変更内容:

1
2
3
4
config.cache_store = :redis_cache_store, {
url: ENV['REDIS_URL'],
ssl: true, # この行はAmazon ElastiCache For Redisの場合のみ。ローカルのDocker開発環境の場合は不要
}

ENV['REDIS_URL']について

ENV['REDIS_URL']については、それぞれ以下のように設定する。

Amazon ElastiCache For Redis の場合

redis://hoge.serverless.apne1.cache.amazonaws.com:6379/0

ローカルのDocker開発環境の場合

redis://redis:6379/0

docker-compose.ymlに以下のように追記する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
web:
environment:
REDIS_URL: 'redis://redis:6379/0'
depends_on:
- redis

redis:
image: redis:latest
ports:
- "6379:6379"
volumes:
- redis-data:/data

volumes:
redis-data:
driver: local

キャッシュを利用するコード

上記の設定完了後、以下のコードでキャッシュが効くようになる。

1
2
3
4
5
6
key = "cache_count_" + params[:id]
result = Rails.cache.fetch(key, expires_in: 5.minutes) do
# キャッシュがなければここが実行される
count = get_count(params[:id])
count
end

と、基本的にはこれだけでOK。

注意点

  • Redisでは正規表現を使ってキャッシュを削除することができる
  • 例えばRails.cache.delete_matched('cache_count_*')
  • ただし、Amazon ElastiCache For Redis は正規表現を使ってキャッシュを削除することができない
  • Amazon ElastiCache For Redis はクラスター構成となっていて、キャッシュの保存先が分散されているため
  • 以下のエラーが発生する
  • CROSSSLOT Keys in request don't hash to the same slot

リストやハッシュをキャッシュする場合

  • 上記の設定では、キャッシュの対象は文字列のみ
  • リストやハッシュをキャッシュする場合は、$redisインスタンスを直接利用する必要がある

$redisの設定

config/initializers/redis.rbを作成し、以下のように記述する。

1
$redis = Redis.new(url: ENV['REDIS_URL'])

リストをキャッシュする場合

1
2
$redis.lpush('list_key', 'value')
$redis.lrange('list_key', 0, -1)

注意点

sslを有効にする場合、Rails.cacheではssl: trueのオプションがあったが、$redisではurlrediss://を指定する必要がある。
例えば、rediss://hoge.serverless.apne1.cache.amazonaws.com:6379/0とすると、sslが有効になる。

VuetifyのバリデーションをJavaScriptで実行する

html

1
2
3
4
5
<v-form ref="form">
<v-text-field
:rules="[rules.required]"
></v-text-field>
</v-form>

JavaScript

1
2
3
4
5
6
7
8
9
10
11
12
13
// バリデーション
let form = ref(null)
const rules = ref({
required: value => !!value || '',
})

const submit = async () => {
const validResult = await form.value.validate()
if (!validResult.valid) {
return
}
//以下、submitの処理
}

【kintone】プラグインアップロード時のタイムアウトエラー

kintone-plugin-uploaderコマンド実行時に以下のエラーが出ました。

エラーが発生しました TimeoutError: Waiting for selector .ocean-ui-dialog failed: Waiting failed: 60000ms exceeded

原因はplugin.zipの指定方法が間違ってました。

以下の通りに修正したらうまくいきました。

1
2
3
4
# 修正前
kintone-plugin-uploader plugin.zip
# 修正後
kintone-plugin-uploader dist/plugin.zip

言われてみればそうなのですが、エラーからは読み取りにくくて苦戦しました。。

Railsでアプリログのフォーマットを変更する方法

Railsでアプリログのフォーマットを変更する方法です。

以下の2ファイルを追加・修正します。

(追加)app/lib/local_dev_log_formatter.rb

1
2
3
4
5
6
7
class LocalDevLogFormatter < ActiveSupport::Logger::SimpleFormatter
def call(severity, timestamp, progname, msg)
formatted_severity = sprintf("%-5s", "#{severity}")
formatted_time = timestamp.strftime("%Y-%m-%d %H:%M:%S.") << timestamp.usec.to_s[0..2].rjust(3)
"[#{formatted_severity} #{formatted_time} ##{Process.pid}] #{msg}\n"
end
end

(修正)config/environments/development.rb

1
2
3
4
5
6
7
8
9
Hoge::Application.configure do

# 中略

config.log_formatter = LocalDevLogFormatter.new # 日時を出力するためにカスタムフォーマッターを指定
logger = ActiveSupport::Logger.new("log/#{Rails.env}.log", 5, 100 * 1024 * 1024)
logger.formatter = config.log_formatter
config.logger = ActiveSupport::TaggedLogging.new(logger)
end

app/lib配下に配置することとconfig.loggerの方にも設定が必要なところが分からなくてハマりました。。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×