Sass の便利な機能「@mixin」の使い方

Sass の便利な機能「@mixin」の使い方について紹介します。

基本的な書き方

基本的な書き方は下記のようになります。

@mixin title_abc($color: #333, $fontSize: 22px) {
  color: $color;
  font-size: $fontSize;
}

.title {
  @include title_abc();
}

.title_light {
  @include title_abc(#777, 20px);
}

「@mixin」で名前と変数、スタイルを定義して、「@include」で呼び出します。

そのまま使いたい場合は、「@include title_abc();」のように引数を渡さずに使い、変更したい場合は「@include title_abc(#777, 20px);」のように引数を渡します。

cssに展開したあとは下記のようになります。

.title {
  color: #333;
  font-size: 22px;
}

.title_light {
  color: #777;
  font-size: 20px;
}

メディアクエリを管理

まず、ブレイクポイントを変数で定義します。
変数で定義しておくことで、あとでの変更が簡単にできます。

$sm: "600px";
$md: "900px";
$lg: "1200px";

@mixinを定義します。
「@content」はスタイルセットを@mixinに渡す機能です。
@includeで書いた内容がこの場所に展開されます。

@mixin media-max($size) {
  @media screen and (max-width: $size) {
    @content;//展開される場所。この場合「.class {color:red}」
  }
}

「@include」で定義した、@mixinを呼び出します。
$lgのところは変数ではなく、「1000px」などのように書くと個別での対応もできます。

@include media-max($lg) { 
  .class {color:red}
}

今回は「$lg: “1200px”」なので下記のように展開されました。

@media screen and (max-width: 1200px) {
  .class {
    color: red;
  }
}

擬似要素で三角形を作る

三角形を作りたい時に用意しておくと便利な@mixinです。
ジェネレータを使わずに作成することができるので、用意しておくと便利です。

@mixin triangle($direction, $width, $height, $color){
  content:"";
  width: 0;
  height: 0;
  border-style: solid;
  display: inline-block;
  $widthNum: $width / 2;
  $heightNum: $height / 2;
  @if ($direction == top) {
    border-width: 0 $widthNum $height $widthNum;
    border-color: transparent transparent $color transparent;
  } @else if ($direction == left) {
    border-width: $heightNum $width $heightNum 0;
    border-color: transparent $color transparent transparent;
  } @else if ($direction == right) {
    border-width: $heightNum 0 $heightNum $width;
    border-color: transparent transparent transparent $color;
  } @else if ($direction == bottom) {
    border-width: $height $widthNum 0 $widthNum;
    border-color: $color transparent transparent transparent;
  }
}

.arrow::after {
  // top:上向き bottom:下向き right:右向き left:左向き
  @include triangle(right, 6px, 10px, blue);
}

展開されるcssは下記のようになります。

.arrow::after {
  content: "";
  width: 0;
  height: 0;
  border-style: solid;
  display: inline-block;
  border-width: 5px 0 5px 6px;
  border-color: transparent transparent transparent blue;
}

remを使用した文字サイズわかりやすくする

フォントサイズをremで指定するときに、1.5remと書くと思うのですが、パッとどれぐらいのサイズかイメージしずらいです。
そのためあらかじめ@mixinを用意しておくとイメージしやすくなります。

@mixin rem($size) {
  font-size: $size + px;
  font-size: ($size / 16) + rem;//既定値を16pxに設定した時
}

h1{
  @include rem(24)
}

p{
  @include rem(16)
}

展開されるcssは下記のようになります。

h1 {
  font-size: 24px;
  font-size: 1.5rem;
}

p {
  font-size: 16px;
  font-size: 1rem;
}

今回はSassの便利な機能「@mixin」の使い方を簡単に紹介しました!
何かの参考になれば幸いです。


Solrの記事リスト(〜2020年12月)

はじめに

ふと気付けばこのブログの Solr の記事が40本を超えていました。Solr タグで検索していただくこともできますが、もう少し見やすくなるようにトピックで分類して記事タイトルとリンクの形でリスト化してみました。

Prometheus連携

パッケージ管理

JSON Request API

Docker

日付表現

SolrCloudのリーダー選出

SolrCloud

インデックス作成

distinct

その他


健康診断で見つかったピロリ菌の除菌と検査

前回の健康診断でピロリ菌に感染しているのがわかったのでピロリ除菌を行いました。

朝と夜にお薬を飲むだけ・・・だけどつい忘れそうになります。薬の入ってる紙に日付を書く欄があったので飲む前に記載することでなんとか飲み逃すことなく薬は飲み切りました。薬を飲んでる最中はいつも行ってるスーパーの特定の弁当が塩辛く感じてコロナで味覚障害とか聞いていたので少し戦々恐々としていましたが単純にピロリ菌除菌の薬自体の副作用が出ただけのようです。

その4週間後に除菌判定の検査。これは袋に息を入れるだけなので検査自体は特に負担のかかるものはなかったです。さらに1週間後にようやく除菌判定の検査結果を聞きに病院に向かい結果は良好!除菌できていました!!1度目の除菌で除菌できない場合があると聞いてたので1回目で済んだのは本当によかった。ただ3ヶ月後に今度は便での検査があるのでそれが済んだらようやく本当に除菌完了です。

発病してからの治療より余裕のあるうちに予防をという点でシステム開発と同じですね!


SolrのCirtcuit Breakerは具体的に何を見ているのか

はじめに

前回紹介した Circuit Breaker には MemoryCircuitBreaker と CPUCircuitBreaker の2種類があります。それぞれメモリとCPUの使い過ぎに対応しているのだなと何となくは想像が付きますが、具体的にはシステムの何を参照しているのかを調べてみました。

MemoryCircuitBreaker

リファレンスによると、JVMのヒープ使用率が設定値を超えると503を返すと書かれています。MemoryCircuitBreaker の実装をみると、取得しているのは ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed() でした。これは現在のヒープ使用量をByteで返すものです。

一方、設定ではヒープの使用率を記述するので、比較するには使用率か使用量かのどちらかに変換して合わせる必要があります。
ソースを確認すると、MemoryCircuitBreaker のコンストラクタで memThreashold を読み込んだときに、ヒープの最大値 * memThreshold / 100 で閾値となるメモリ使用量を計算しておき、MemoryMXBean から取得したメモリ使用量がその値を超えたらリクエストを拒否するという実装になっていました。

CPUCircuitBreaker

CPUCircuitBreaker で監視しているのは ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverate() なので OS から取得するロードアベレージです。設定するのはCPU使用率なので、こちらも何らかの変換をしているのかと思いきや、何とソースコードではCPU使用率の閾値(%)とロードアベレージ(0以上の数値、CPUの数にもよるが通常はせいぜい10未満)を直接比較していました。

これだと使用率のつもりで75などと設定しても全く引っ掛からないのはずで不思議に思って調べてみたところ、どうやらバグのようで JIRA に Issue が作られていました。

CPU circuit breaker needs to use CPU utilization, not Unix load average

タイトルそのまんまですね。
ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverate() の代わりに ManagementFactory.getOperatingSystemMXBean().getSystemCPULoad() (0.0-0.1の間のCPU使用率)を使うことが提案されており、近いうちに修正されることと思います。


Solr 8.7で追加されたCircuit Breaker機能

はじめに

Solr 8.7 に Circuit Breaker 機能が追加されました。
いわゆるブレーカーは一定以上の電流が流れたときに回路を遮断する仕組みです。Solr においては想定を超える負荷が掛かったときにサーバが落ちる前にリクエストの受付を停める仕組みになっています。

設定方法

Solr 8.7 に付属の solrconfig.xml には Circuit Breaker 関係の設定が追加されています。説明のコメント部分を除くと以下のような内容です。

    <circuitBreakers enabled="true">
      <!--
       <memBreaker enabled="true" threshold="75"/>
      -->
      <!--
       <cpuBreaker enabled="true" threshold="75"/>
      -->
    </circuitBreakers>

circuitBreakers 要素の enabled 属性が true のときだけ Circuit Breaker 機能が有効になります。
他の部分はコメントを外して設定を有効にすれば良いのかと思ったのですが、リファレンスにはちょっと違うことが書いてあります。リファレンスによると、JVMのヒープ使用率ベースの Circuit Breaker の設定は以下の2項目です。

<str name="memEnabled">true</str>
<str name="memThreshold">75</str>

また、CPU使用率ベースの Circuit Breaker の設定は以下の通りと記載されています。

<str name="cpuEnabled">true</str>
<str name="cpuThreshold">75</str>

CircuitBreakerManager.java を確認すると以下のような読み込み処理があるので、solrconfig.xml ではなくリファレンスの記述の方が正しいようです。

      if (args != null) {
        cpuCBEnabled = Boolean.parseBoolean(args._getStr("cpuEnabled", "false"));
        memCBEnabled = Boolean.parseBoolean(args._getStr("memEnabled", "false"));
        memCBThreshold = Integer.parseInt(args._getStr("memThreshold", "100"));
        cpuCBThreshold = Integer.parseInt(args._getStr("cpuThreshold", "100"));
      }

以下は SearchHandler で circuitBreakerManager によるチェックを実行している箇所です。チェックに引っ掛かると SolrQueryResponse オブジェクト(rsp)に SERVICE_UNAVAILABLE をセットして終了していることが分かります。

    if (req.getCore().getCircuitBreakerManager().isEnabled()) {
      List trippedCircuitBreakers;

      if (timer != null) {
        RTimerTree subt = timer.sub("circuitbreaker");
        rb.setTimer(subt);

        CircuitBreakerManager circuitBreakerManager = req.getCore().getCircuitBreakerManager();
        trippedCircuitBreakers = circuitBreakerManager.checkTripped();

        rb.getTimer().stop();
      } else {
        CircuitBreakerManager circuitBreakerManager = req.getCore().getCircuitBreakerManager();
        trippedCircuitBreakers = circuitBreakerManager.checkTripped();
      }

      if (trippedCircuitBreakers != null) {
        String errorMessage = CircuitBreakerManager.toErrorMessage(trippedCircuitBreakers);
        rsp.add(STATUS, FAILURE);
        rsp.setException(new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE, "Circuit Breakers tripped " + errorMessage));
        return;
      }
    }

おわりに

Circuit Breaker 機能は地味ながら、安定運用のためには便利な機能といえます。今後監視項目をプラグインできるようになる可能性もあり、要注目です。