Total Pageviews

2017/04/05

[Failsafe] Retry with Fallback

Scenario
If we cannot get connection, then we will retry 5 times with 2 seconds delay.
If we fail to retry with 5 times, then we will pause X minutes then retry again.
How to implement it?


How-to
You can make good use of failsafe to fulfill this implement.
In this exampe, it will demonstrate:
1. create a retry policy with 5 max retries and have 2 seconds delay among retries
2. If you got failed execution, it will retry again after 5 seconds.
 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package albert.practice.retry;

import java.sql.Connection;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import lombok.extern.slf4j.Slf4j;
import net.jodah.failsafe.Failsafe;
import net.jodah.failsafe.RetryPolicy;

@Slf4j
public class RetryTest {

    private int count = 0;

    public static void main(String[] args) throws ConnectionException {
        new RetryTest().connectWithRetry();
    }

    public Connection connectWithRetry() {
        // create a retry policy with 5 max retries and have 2 seconds delay among retries 
        RetryPolicy retryPolicy = new RetryPolicy();
        retryPolicy.retryOn(ConnectionException.class).withDelay(2, TimeUnit.SECONDS)
                .withMaxRetries(5);

        // Using Fallbacks allow you to provide an alternative result for a failed execution. 
        // In this example, it will retry again after 5 seconds.
        Connection conn = Failsafe.with(retryPolicy).withFallback(() -> retryIfFail())
                .get(() -> connect());

        return conn;
    }

    public void retryIfFail() throws InterruptedException {
        log.debug("GG at " + getCurrentTime());
        Thread.sleep(5000);

        log.debug("retry....." + getCurrentTime());
        connectWithRetry();
    }

    public Connection connect() throws ConnectionException {
        log.debug(" time = " + getCurrentTime());
        Connection conn = null;
        if (count < 9) {
            count++;
            throw new ConnectionException("connection fail!");
        } else {
            log.debug("get connection successfuly...");
        }
        return conn;
    }

    private String getCurrentTime() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
        return dateFormat.format(new Date());
    }
}


Console log:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:13.832
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:15.837
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:17.837
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:19.837
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:21.838
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:23.839
DEBUG albert.practice.retry.RetryTest - GG at 2016/11/05 11:42:23.839
DEBUG albert.practice.retry.RetryTest - retry.....2016/11/05 11:42:28.839
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:28.839
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:30.839
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:32.839
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:34.840
DEBUG albert.practice.retry.RetryTest - get connection successfuly...

Reference
[1] https://github.com/jhalterman/failsafe#fallbacks

2017/04/04

[Angular2] fail to load data items in ng2-select component

Problem
I am using ng2-select to implement a dropdown list function.
But my dropdown list cannot be showed just like the example:


Here is my code snippet:
   <div class="row">
    <div class="col-sm-12">
        <div class="form-group">
           <label> 負責人員 </label>
           <div style="width: 300px; margin-bottom: 20px;">
              <ng-select [allowClear]="true" 
                         [items]="items" 
                         [data]="selectedItem"
                         (data)="refreshValue($event)" 
                         (selected)="selected($event)"
                         (removed)="removed($event)" 
                         placeholder="請選擇負責人員">
              </ng-select>
           </div>
        </div>
    </div>
   </div>


How-to
Owning to the data items in ng2-select example is static:

The data items in my function which will retrieve them from 
database, so we need to wait until data items had been finished then create the DOM element.

Owing to I do not know how long I need to wait, so I add *ngIf in the first div tag.
   <div class="row" *ngIf="items && items.length > 0">
    <div class="col-sm-12">
        <div class="form-group">
           <label> 負責人員 </label>
           <div style="width: 300px; margin-bottom: 20px;">
              <ng-select [allowClear]="true" 
                         [items]="items" 
                         [data]="selectedItem"
                         (data)="refreshValue($event)" 
                         (selected)="selected($event)"
                         (removed)="removed($event)" 
                         placeholder="請選擇負責人員">
              </ng-select>
           </div>
        </div>
    </div>
   </div>


Reference
[1] https://valor-software.com/ng2-select/


2017/04/03

[UML] How to Draw a Scheduler Service in Sequence Diagram

Problem
Assume I have a HeartBeatService and HeartbeatProducerService.
HeartBeatService will call HeartbeatProducerService every 5 seconds to check system is alive or not. 

How to show this kind of scheduler job in sequence diagram.


How-to
You can add a loop combined fragment in sequence diagram, it looks like:



2017/04/02

[Failsafe] Simple, sophisticated failure handling

Scenario
We have a Java application to connect to OPC server, if it fail to connect to OPC server it will retry 5 times.


How-to
You can make good use of Failsafe to fulfill this requirement. 
Failsafe is a lightweight, zero-dependency library for handling failures. It was designed to be as easy to use as possible, with a concise API for handling everyday use cases and the flexibility to handle everything else.

Maven dependency:
1
2
3
4
5
6
7
<dependencies>
   <dependency>
      <groupId>net.jodah</groupId>
      <artifactId>failsafe</artifactId>
      <version>0.9.5</version>
   </dependency>
</dependencies>


If I catch ConnectionException, it will do retry, the retry policy is as bellows:

  • it will delay 2 seconds between retries
  • it will retry 5 times at most


 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
26
27
package albert.practice.retry;

import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import lombok.extern.slf4j.Slf4j;
import net.jodah.failsafe.Failsafe;
import net.jodah.failsafe.RetryPolicy;

@Slf4j
public class RetryTest {

    public static void main(String[] args) throws ConnectionException {
        @SuppressWarnings("unchecked")
        RetryPolicy retryPolicy = new RetryPolicy().retryOn(ConnectionException.class)
                .withDelay(2, TimeUnit.SECONDS).withMaxRetries(5);
        Failsafe.with(retryPolicy).run(() -> new RetryTest().connect());
    }

    public void connect() throws ConnectionException {
        log.debug("time=" + new Date(Calendar.getInstance().getTimeInMillis()));
        if (true) {
             throw new ConnectionException("connection fail!");
        }
    }
}



Reference
[1] https://github.com/jhalterman/failsafe

2017/04/01

[閱讀筆記] Waltzing with Bears (1/2)


  1. 經營管理是企業體的成長與永續之道,投資理財是個人的安身之道,而經濟趨勢則是會影響這兩者的變數
  2. 風險管理的事務,著重於成因風險(cause risk)的管理,亦即你能管理的部分
  3. 風險就是還沒發生的問題,問題是已經發生的風險
  4. 風險管理是在問題發生之前,預先思考應變措施的過程;危機管理則是在問題發生之後,嘗試處理善後
  5. 軟體工程規範原地踏步了許多年,他始終缺乏跟上資訊時代並滿足資訊社會所需要的成熟工程規範
  6. 很多軟體專案會失敗,並非風險管理方法不好,而是他根本就沒花任何功夫在風險管理上,反而在祈禱風險不會發生
  7. 風險管理就是把不確定性侷限在一個範圍內,或許你害怕僅憑少量資訊就要把問題解決掉。但是,若連這點資訊都沒有,情況會更糟糕。無窮無盡的不確定性,結果不是讓人過分保守,就是讓人變得莽撞,兩者都不是好事
  8. 進行風險管理不會使問題消失,只能保證不會讓你遭受突如其來的衝擊,殺的你措手不及
  9. 當你在祈禱所有的好運都降臨在你身上,當運氣其成為你整體策略的一部分時,小心,你的麻煩要來了
  10. 風險管理往往能提供你想要的更多事實真相
  11. 有些組織一廂情願的相信可以控制一切,即使心知肚明這並非事實,還是慣用控制的假象來蒙蔽現實。最常見的特徵,就是一開始弄出一個精確到令人可笑的預估結果,事後卻證明他跟事實差了十萬八千里
  12. 你可以管理風險,但不可能使風險消失
  13. 在最糟糕的組織中,報壞消息的人會被懲罰,但壞結果卻不會被檢討。當你提出風險時,就會有另外一位同儕會搶著說包在他身上,他一定可以如期完成。在這種文化中,大家都會先把牛吹大,因為這遠比按時交貨來得重要。如果再這種公司上班,把風險評估收起來,自己私底下用就好
  14. 組織不允許不確定性存在,風險管理就不用做了。這樣的組織,成員不可以對「一切如期完成」表現出一丁點的疑慮。事情做錯沒關係,就是不可以不確定
  15. 組織常常缺少能發出「災難」訊號的自主神經系統,常常自以為掌握了所有風險(潛在問題),其實只掌握了一部份而已(已有解決方案的潛在問題)
  16. 當你決定忽略某個風險時,就等於要賭運氣,賭這個風險不會發生
  17. 當專案包裝成一項挑戰時,就相當於強迫你去賭運氣。例如,你是全公司最後的希望,希望你能在這個月底完成這個專案
  18. 專案一開始就以個人挑戰的形式出發,便很難有明智的風險管理,這種專案就是在賭運氣
  19. 做軟體專案,你一定要把失敗的可能性限制在一定範圍內
  20. 我們在做預估的時候,記得把預估背後依賴的假設統統列舉出來
  21. 專案偏離時程,陷入泥沼,很少是因為工作比預期的更花時間,多半是為了處理原本沒有規劃到的事情
  22. 越棘手的風險,高層主管想弄走他的壓力就越大。根據經驗,高層主管若抓狂到某種地步,就比較不會想去了解為什麼風險會消失,反正只要它不見了就好
  23. 在軟體專案中,你不知道的問題,那通常就是風險所在。無論是什麼事情不知道,只要會造成不利的負面影響,就是風險。蒐集各種「我不知道」的問題,把不知道的根本原因找出來,你就可以得到一份完整的風險列表


2017/03/31

2017/03 Travel

奮起湖
DSC01349

DSC01343

DSC01345

DSC01364


台大杜鵑節
DSC01499

台北北門
DSC01391

DSC01395

2017/03/10

[Agnular2] Notifying parent Components that something has happened via events

Scenario

If we would like to tell the parent Component that the child component has added or deleted subtask. How to implement in Angualr2 ?


How-to
To create a custom event, we can use the new @Output decorator. So let's start by creating a new instance of an Event Emitter and decorate the property with the @Output decorator.

Then we've got an event emitter in place, let's call its emit method, callParent(), to raise the event and pass to parent component. 

The child component's code snippet looks like:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@Component({
  selector: 'sub-task',
  directives: [MODAL_DIRECTIVES, SELECT_DIRECTIVES, NgClass],
  providers: [SubtaskService, UserService, IssueService, ProjectService],
  templateUrl: 'sub.task.html'
})
export class SubTaskComponent implements OnInit {

  @Input() issue: Issue;
  @Input() watchers: Watcher[];

  @Output() refreshIssueEvent = new EventEmitter();
  
  callParent() {
    this.refreshIssueEvent.emit(this.issue.id);
  }
  
  //...
}  


The parent component receives that event and its payload. We use event binding to bind to this notify event and call a method.

Our final step is to provide the refreshIssue method to execute when the notify event occurs. 
1
2
3
<div class="container" *ngIf="issue.id">
  <sub-task [issue]="issue" [watchers]="issue.watchers" (refreshIssueEvent)="refreshIssue($event)"></sub-task>
</div>

We have to pass the $event to parent component's handler because that variable holds the event payload.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@Component({
  selector: 'issue-detail',
  templateUrl: 'issue.detail.html',
  providers: [IssueService]
})
export class IssueDetailComponent implements OnInit, OnDestroy {
  refreshIssue(issueId: number){
    this.issueService.getIssue(issueId.toString()).subscribe(
      data => {
        this.issue = data;
      }
    );
  }
  //...
}

2017/03/09

[Angular2] Pass data from parent to child with input binding

Scenario


If we had two html pages which has parent and child relationship. If we would like to pass parameters from parent to child, how to implement in Agnular2?

How-to
Step 1. Define the input parameter names in child component which typically adorned with @Input decorations., the code snippet is as bellows:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Component({
  selector: 'sub-task',
  directives: [MODAL_DIRECTIVES, SELECT_DIRECTIVES, NgClass],
  providers: [SubtaskService, UserService, IssueService, ProjectService],
  templateUrl: 'sub.task.html'
})
export class SubTaskComponent implements OnInit {

  @Input() issue: Issue;
  @Input() watchers: Watcher[];
  
  // ...
}

Step 2. The Parent page, issue.detail.html, is binding its master string property to the child's property. The code snippet is as follows:
1
2
3
<div class="container" *ngIf="issue.id">
  <sub-task [issue]="issue" [watchers]="issue.watchers"></sub-task>
</div>



2017/03/08

[Design Pattern] Command Pattern

在 97 Things Every Programmer Should Know 一書中提到:
雖然在一般遇到的案例裡,使用 if - then - else 比多型更實用些,但絕大多數用 polymorphism 的寫作風格會讓程式碼更精簡、更易讀,且更少脆弱的程式碼。所以在我們的程式碼裡,要是錯過使用 polymorphism 的機會,便會逐漸增加  if - then - else 敘述句的數量。試試 command  pattern 吧

假設我有一個機器人物件,他會執行前進、後退、左轉與右轉,這四種指令

package albert.practice.designpattern.command;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@AllArgsConstructor
@Data
@Slf4j
public class Robot {

    private String robotName;

    public void goAhead() {
        log.debug(robotName + " 前進 !");
    }

    public void turnLeft() {
        log.debug(robotName + " 左轉 !");
    }

    public void turnRight() {
        log.debug(robotName + " 右轉 !");
    }

    public void turnBack() {
        log.debug(robotName + " 後退 !");
    }
}


另外建立一個 enumeration 來判斷,此次呼叫要執行哪一個指令
package albert.practice.designpattern.command;

public enum CommandEnum {
    GO_HEAD, TURN_BACK, TURN_RIGHT, TURN_LEFT;
}


建立機器人物件與執行指令如下:
package albert.practice.designpattern.command;

public class RobotTestClient {

    public static void main(String[] args) {
        Robot robot = new Robot("瓦力");

        RobotTestClient client = new RobotTestClient();
        client.executeRobot(robot, CommandEnum.GO_HEAD);
        client.executeRobot(robot, CommandEnum.TURN_LEFT);
        client.executeRobot(robot, CommandEnum.TURN_RIGHT);        
    }

    public void executeRobot(Robot robot, CommandEnum command) {
        if (CommandEnum.GO_HEAD == command) {
            robot.goAhead();
        } else if (CommandEnum.TURN_BACK == command) {
            robot.turnBack();
        } else if (CommandEnum.TURN_LEFT == command) {
            robot.turnLeft();
        } else if (CommandEnum.TURN_RIGHT == command) {
            robot.turnRight();
        }
    }

}



在上述的程式碼就會發現,如果指令越來越多,就會有越來越多的 if-else 判斷式,此時就可以套用 command pattern

首先,先建立 Command interface
package albert.practice.designpattern.command;

public interface Command {
    void execute();
}



然後,分別建立四個指令的 classes,並實作 Command interface
前進指令:
package albert.practice.designpattern.command;

public class GoAheadCommand implements Command {

    private Robot robot;

    public GoAheadCommand(Robot robot) {
        super();
        this.robot = robot;
    }

    @Override
    public void execute() {
        this.robot.goAhead();
    }

}


後退指令:
package albert.practice.designpattern.command;

public class TurnBackCommand implements Command {
    private Robot robot;

    public TurnBackCommand(Robot robot) {
        super();
        this.robot = robot;
    }

    @Override
    public void execute() {
        this.robot.turnBack();
    }

}



向左轉指令:

package albert.practice.designpattern.command;

public class TurnLeftCommand implements Command {
    private Robot robot;

    public TurnLeftCommand(Robot robot) {
        super();
        this.robot = robot;
    }

    @Override
    public void execute() {
        this.robot.turnLeft();
    }

}



向右轉指令:
package albert.practice.designpattern.command;

public class TurnRightCommand implements Command {
    private Robot robot;

    public TurnRightCommand(Robot robot) {
        super();
        this.robot = robot;
    }

    @Override
    public void execute() {
        this.robot.turnRight();
    }

}



建立機器人物件與操作指令,程式修改如下:

package albert.practice.designpattern.command;

public class RobotTestClient {

    public static void main(String[] args) {
        Robot robot = new Robot("瓦力");
        new GoAheadCommand(robot).execute();
        new TurnLeftCommand(robot).execute();
        new TurnRightCommand(robot).execute();
    }

}



2017/03/07

[Redmine] How to get mail notification value in user page

Problem
I am trying to get admin value from the redmine user object. 
But I cannot get admin value, no matter using Java API or Rest API.
It can only retrieve very limited information:



How-To
We can make good use of jsoup to parse html page and get value from the specific html element.

Firstly, checking the drop down list element in html. 


Secondly, using jsoup to parse HTML
1
2
3
4
5
6
7
8
9
    String url = "http://192.168.0.1/users/" + userId + "/edit";
    Document document = Jsoup.connect(url).get();
    Elements mailNotificationElements = document.select("[name=user[mail_notification]]").select("option");
    for (Element element : mailNotificationElements) {
        if ("selected".equals(element.attr("selected"))) {
            log.debug("the mail_notification value = " + element.val());
            break;
        }
    }


Reference
[1] https://jsoup.org/



2017/03/06

[Redmine] How to get admin value in user page

Problem
I am trying to get admin value from the redmine user object. 
But I cannot get admin value, no matter using Java API or Rest API.
It can only retrieve very limited information:



How-To
We can make good use of jsoup to parse html page and get value from the specific html element.

Firstly, checking the checkbox element in html. 
We can find out the element name and the checked checkbox will add checked="checked" attribute.

If the checkbox does not be checked, it will not have checked="checked" attribute.


Secondly, using jsoup to parse HTML
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
    String url = "http://192.168.0.1/users/" + userId + "/edit";
    // Connect to redmine url and get HTML document
    Document document = Jsoup.connect(url).get();
    
    // Find elements that match [name=user[admin]]
    Elements adminElements = document.select("[name=user[admin]]");
    for (Element element : adminElements) {
       // if the element has checked="checked" attribute, it means this user is administrator, 
       // or this user is a normal user
       if ("checked".equals(element.attr("checked"))) {
           log.debug("this user is admin");
           break;
       }
    }


Reference
[1] https://jsoup.org/