DockerコンテナへのJDKへのインストールが失敗する

1か月前は普通にできていたDockerコンテナ(Ubuntu)へのJDKのインストールが失敗するようになった。

Err:186 http://220.152.35.154:80/data/02c924ae5a628323/archive.ubuntu.com/ubuntu bionic-updates/universe amd64 openjdk-8-jdk amd64 8u181-b13-1ubuntu0.18.04.1                            
  Redirection loop encountered
Fetched 94.1 MB in 3min 33s (441 kB/s)                                                                                                                                                   

こんな感じのエラーが出て失敗する。

調べてみると、5ちゃんねるにJCOMの回線を使っていて 同様の症状が出ている書き込みを見つけた。 確かにうちのもJCOM回線だ。

どうやらJCOMがキャッシュしているパッケージファイルが破損してしまっているのが原因とのことだったので archive.ubuntu.comからダウンロードするのをやめ、 ftp.iij.ad.jpからダウンロードするようにしたところ上手くいくようになった。

具体的には以下のようなコマンドをたたき、apt install し直す形になる。

sed -i 's|http://archive.ubuntu.com/ubuntu/|http://ftp.iij.ad.jp/pub/linux/ubuntu/archive/|g' /etc/apt/sources.list

こういうの防ぐ方法ないのかなぁ。

RxJSを使い、配列のデータを1件ずつ待ちを挟みながら処理していく。

前回の記事をRxJSを使って書き直したような感じの内容。 前回との違いは元になるデータが配列ってところくらい。

private messages = [];
private messageArray = [{message: 'テストメッセージ1'}, {message: 'テストメッセージ2'}]
const delayObservable = Rx.Observable.empty().delay(1000); // 1秒待ちを入れるobservableを作っておく
let messageObservable = Rx.Observable.from(this.messageArray)
    .concatMap(msg => {
        return Rx.Observable.empty().concat(delayObservable).concat(Rx.Observable.of(msg)); // 1秒のディレイを挟みつつ、メッセージをsubscribeのコールバックへ流す
    });

const initMessageSubscription = messageObservable.subscribe(
    (msg) => {
        this.messages.push(msg); // メッセージを順次処理する
    },
    (err) => {
        console.error(err);
    },
    () => {
        initMessageSubscription.unsubscribe(); // 終わったらunsubscribeする。
    }
);

cyubachi.hatenablog.com

Promiseを使って非同期の処理を直列に処理する方法。

4~5年くらい前にPromiseがイマイチ理解できずにコールバックのネストで済ませてしまった問題をようやく解決できた。。。

Promise.resolve()
.then(() => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            // 何か処理を書く
            resolve();
        }, 1000);
    });
})
.then(() => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            // 何か処理を書く
            resolve();
        }, 1000);
    });
});
````

Clojureで特定の条件になるまで待つ

この例だと10秒待つ感じ。
if の条件を関数とかにして引数でもらうようにすれば大体のパターンに対応できる。

(defn wait-10sec []
  (loop [i 0]
    (if (< i 10)
      (do
        (Thread/sleep 1000)
        (println i)
        (recur (+ i 1))))))

これはなんかライブラリがありそうな気がするな。

ループの途中でreturn(break)したい

気が付いたら前回のポストからすでに2年弱。早いもんですね。。。。

Pythonでいうところの

objs = [{"a": 1, "text": "test 1 message"},
        {"a": 2, "text": "test 2 message"},
        {"a": 3, "text": "test 3 message"}]

for o in objs:
    if o["a"] == 3:
        return o

こんなことをClojureで実現したかったので考えてみたけど こんなのしか浮かばなかった。

user> (def objs [{:a 1 :text "test 1 message"}
                 {:a 2 :text "test 2 message"}
                 {:a 3 :text "test 3 message"}])
#'user/objs
user> (loop [o objs]
        (when-not (empty? o)
          (if (= 3 (-> o first :a)) ;; ここの3を変える
            (-> o first)
            (recur (rest o)))))

pythonで3行なんだし、もうちょっと縮められないかまた考えておこう。

それにしても、よくこんなことも知らずに今までやってこれてきたもんだ。

2018-04-03 追記

id:ayato0211 あやぴーさん曰く、この例程度であれば filter + first でも良いとのこと。

(first (filter #(= 3 (:a %)) objs))

やっぱ、clojure使ってる人はこっちの方がわかりやすかったりするのかな?

あと、reduce/reducedなんてのもあるらしい。

(reduce #(if (= (:a %2) 3) (reduced %2)) nil objs)

あやぴーさん、ありがとうございます。とても勉強になりました。 m(_ _)m

Selmerを使ってみる

Hiccupにどうしても慣れることができなかったので、Djangoにインスパイアされたと言われるSelmerがどんなものか軽く動かしてみることにした。

project.cljの:dependenciesに以下を追加

[selmer "1.0.7"]

resource/templates配下に

  • layout.html
  • user/login.html

を用意

<!-- resource/templates/layout.html -->
<html lang="ja">
  <head>
    <title>title</title>
  </head>
  <body>
    {% block body %}{% endblock %}
  </body>
</html>
<!-- resource/templates/user/login.html -->
{% extends "layout.html" %}
{% block body %}
<form action="/login" method="post">
  <div><input type="text" name="email" value="{{email}}"/></div>
  <div><input type="password" name="password" value="{{password}}"/></div>
  <div><input type="submit" value="submit"/></div>
</form>
{% endblock %}

画面表示用の関数でrender-file を使ってテンプレートの呼び出しとコンテキストの設定

; core.clj
(ns selmer-example.core
  (:require ...省略...)
  (:use [selmer.parser :refer [render-file set-resource-path!]]))
; project.cljの:resource-paths に resourcesが指定されている必要がある
(set-resource-path! (clojure.java.io/resource "templates"))

(defn login-view
  [{email :email password :password :as params}]
  (println params)
  (render-file "user/login.html" {:email email :password password}))

...省略....

すんなり動いてくれた。これなら十分実用できそうな気がする。

ループを回して配列に値を追加する

Pythonだとこんな感じの処理をClojureで書くとどうなるかパッとでてこなかったのでこれもメモ

>>> b = []
>>> for i in range(0, 10):
...     b.append({"v": i})
... 
>>> b
[{'v': 0}, {'v': 1}, {'v': 2}, {'v': 3}, {'v': 4}, {'v': 5}, {'v': 6}, {'v': 7}, {'v': 8}, {'v': 9}]
(loop [i 0
       v []]
  (if (< i 10)
    (recur (inc i) (conj v {:v i}))
    v))
[{:v 0} {:v 1} {:v 2} {:v 3} {:v 4} {:v 5} {:v 6} {:v 7} {:v 8} {:v 9}]  

もうちょっといい書き方ある気がする。