2018年12月29日 星期六

PostgreSQL 在 READ_COMMITTED 模式的特性

在閱讀官方文件時,雖然官方文件是寫得挺詳細的,但有種很像是把程式邏輯攤出來解釋的感覺,有時候需要稍微思考一下才能把前後的描述合併起來理解。

non-repeatable read 和 phantom read

在 PostgreSQL 的文件中,描述到 SQL 標準對於錯誤的描述,分別有以下的敘述在描述 non-repeatable read 和 phantom read:

nonrepeatable read
A transaction re-reads data it has previously read and finds that data has been modified by another transaction (that committed since the initial read).

phantom read
A transaction re-executes a query returning a set of rows that satisfy a search condition and finds that the set of rows satisfying the condition has changed due to another recently-committed transaction.

本來對於兩者的差別感覺不是非常明顯,因此查了一下。看了 wikipedia 的描述以後,發現其實也蠻好懂的:

A non-repeatable read occurs, when during the course of a transaction, a row is retrieved twice and the values within the row differ between reads.

A phantom read occurs when, in the course of a transaction, two identical queries are executed, and the collection of rows returned by the second query is different from the first.

也就是說,當在交易中連續讀取兩次的時候,non-repeatable read 指的是讀取到的資料列的內容不一樣,而 phantom read 指的是讀取到的資料列不一樣,例如第一次讀到 #1、#2、#3,第二次讀到 #1、#4,每個資料列的內容都一樣,但符合條件的資料列們不同。(這段描述總覺得好難用中文寫 XD)

參考資料
  1. What is the difference between Non-Repeatable Read and Phantom Read?
  2. Wikipedia: Isolation (database systems)

(暫存) Java 物件的記憶體消耗量

參考資料
  1. Memory consumption of popular Java data types part 1, part 2
  2. On the memory usage of maps in Java

2018年12月12日 星期三

在 Spring Boot 中使用 Jersey

Spring Boot 作為 Spring Framework 的入門套件,底下可以抽換不同的 RESTful 架構,預設雖然會使用 Spring MVC,但其實需要的話也可以抽換成像是 Jersey 或者其他的架構。在這裡要紀錄的就是使用 Jersey 作為 RESTful 架構的方法。

2018年12月7日 星期五

在單元測試時避免 CommandLineRunner 被執行

最近第一次嘗試寫基於 Spring Boot 的應用程式,使用了 CommandLineRunner 來作為應用程式的入口。寫的過程因為想要方便後面做單元測試,因此盡可能地把商業邏輯都寫在 CommandLineRunner 裡頭。不過結果最後在跑單元測試時,卻發現 SpringBootTest 啟動的程序會先執行 CommandLineRunner….囧rz。

2018年11月16日 星期五

Angular Universal 伺服器渲染

目前覺得 [3] 解釋地比較詳細,官方文件 [1] 寫得有點籠統。

如果嘗試從 Java 的角度來理解整個 Angular Universal 相關的東西的話,好像是這麼理解的:

  • Angular、Angular Universal 可以看成是 Kotlin 語言;Node.js 可以看成是 Java 語言。
  • Angular、Angular Universal 寫出來的檔案好像都是 .ts 檔,也就是 TypeScript。這些檔案必須經過編譯,把他們翻譯成 JavaScript;若以 Java 的領域來理解,就像是 Kotlin 也是個 JVM 語言,但真正要在 JVM 上執行前,需要先透過編譯或者直譯器把 Kotlin 的語法翻譯成 Java 的語法。
  • 在查 Angular Universal 時常常會看到 Express 這玩意兒,Express(ExpressJS)對照 Java 的話比較像是 Spring MVC 或者 Jersey 這類 Web 框架。它的程式碼應該是用來告訴 Node.js 要如何解析、處理和回應 HTTP request。

所以整個 Angular Universal 的伺服器渲染,大體上要做的程序會是這樣:

  1. 以 Node.js 啟動的 Web 伺服器程序負責接收 HTTP Request。
  2. HTTP Request 會由 Node.js 上執行的 ExpressJS 程式碼來處理。
  3. ExpressJS 的程式碼去呼叫 Angular Universal 的模組(即 renderModuleFactory()),進行 pre-rendering。
  4. Angular Universal 回覆渲染後的結果給 ExpressJS,ExpressJS 再回覆給客戶端。
參考資料
  1. Angular Universal
  2. 透過 Angular CLI 1.6 將現有專案加入 Angular Universal 伺服器渲染功能
  3. Angular开发实践(六):服务端渲染
  4. Angular server-side rendering in Node with Express Universal Engine
  5. How to build an Angular App with Server-Side Rendering
  6. Angular 6 – Configure Angular Universal with pm2

2018年11月8日 星期四

org.hibernate.QueryException: could not resolve property: “xxx”

寫 Spring Data JPA 或者 Hibernate 時很重要的一點,就是在定義 Repository 時,對應的欄位要用 Entity 裡的變數名字,而不是實際資料庫裡的資料欄位名字。這也包括了當要使用 Pageable 等物件時,物件裡宣告的欄位也要用 Entity 的變數名字。

參考資料
  1. 数据库异常整理:org.hibernate.QueryException: could not resolve property: “xxx”
  2. SSH整合报错:org.hibernate.hql.internal.ast.QuerySyntaxException: User is not mapped[......]

2018年11月2日 星期五

Billions of Messages a Day - Yelp's Real-time Data Pipeline

- Yelp 即時 Data Pipeline 如何處理每天數十億的訊息量
- 如何將 MySQL Table 內容即時串流到 Kafka
- 串流時如何處理不同資料庫 Scheme
- 利用 PaaSTA 與 Storm 來解決即時串流問題
- 如何使用 Saleforce Connector 整合 Saleforce
- 如何將 Kafka 的資料即時串流到 Redshift
- 將 Yelp 的 Data Pipeline 開源
- 如何提升 Yelp MySQLStreamer 效能 3X 倍
- 如何確保從頭到尾的串流資料無誤 (MySQL -> Redshift)
- 將 Yelp Data Pipeline 結合 ElasticSearch 以利搜尋

https://engineeringblog.yelp.com/2016/07/billions-of-messages-a-day-yelps-real-time-data-pipeline.html

2018年10月23日 星期二

在 Spring Data JPA 中使用 AUTO_INCREMENT

快速紀錄~使用 @Id 和 @GeneratedValue 就可以用自動遞增的 Primary Key 了。不過如果不想要讓 Hibernate 自己產生 ID,而是直接靠資料庫自行產生的話,可以設定 @GeneratedValue 的屬性 strategy = GenerationType.IDENTITY。

參考資料
  1. Spring Data JPA; save() auto increment primary key error
  2. JPA EclipseLink DatabaseException: 'table foo.SEQUENCE doesn't exist'

2018年10月17日 星期三

(暫存) 追蹤智能合約

之前看到人家說 web3.py 有 bug,好像追蹤不到,不過現在看 issue 似乎是在新版解決了的樣子,之後要找個時間來實驗一下。

不過如果連接的是 infura 的話,因為 infura 不支援 filter event,所以好像無法靠 Contract Events 追蹤。

參考資料
  1. Empty event log #730
  2. Event logs? Am I doing something wrong?
  3. Listen to filtered events using web3js 0.19 (provided by infura)

編譯 Solidity 智能合約

快速紀錄,因為需要讓 web3.py 使用合約,官方的範例是寫說可以用程式碼直接編譯,不過好像需要環境本身的支援,感覺很麻煩 XD。所以直接在 Windows 裝了 Solidity 的編譯程式 solc,然後執行以下的指令(假設要編譯的智能合約的檔名叫做 contract.sol):

solc --combined-json abi,bin contract.sol > contract.json

以上的指令會建立 abi,並把智能合約的原始碼編譯成 hex 表示的字串,然後寫成一個 JSON 檔。JSON 檔的格式大略會長成這樣:

{
	"contracts": {
		"./XXX.sol:XXX": {
			"abi": "....",
			"bin": "...."
		},
		"./OOO.sol:OOO": {
			"abi": "....",
			"bin": "...."
		}
	},
	"version": "0.4.25+commit.59dbf8f1.Windows.msvc"
}

在這個範例中,是假設要編譯的智能合約包含了超過一個合約,也就是智能合約會引用其他智能合約的狀況。因此編譯出來會有很多個合約一起包在這個 JSON 裡,而每個合約都會有 abi 和 bin 兩個 key,反映我們的指令要求的輸出 abi 和 bin。

參考資料
  1. Installing the Solidity Compiler
  2. Ethereum Dapp初心者之路(7): web3.eth.compile.solidity()替代方案

2018年9月19日 星期三

在 AWS Lambda 執行 web3.py

這篇要紀錄想要在 AWS Lambda 上執行 web3.py 之前需要先做的準備。因為 web3.py 用了一些 C/C++ 編譯的函式庫,因此必須要事先準備好能夠在 AWS Lambda 上執行的編譯後結果。主要步驟也可以參考 [2-3]。

2018年9月14日 星期五

在 Sonatype Nexus 2 上設定 HTTPS

之前一直用 HTTP,但覺得 HTTP 很不安全,所以趁著這次升級 Sonatype Nexus 的時候,一併來實驗啟用 HTTPS。

2018年9月6日 星期四

使用 Python 存取 Ethereum:透過 web3.py

想要透過 Python 存取 Ethereum,從 Ethereum 官方的 Github 中可以看到有兩種套件可以達成:web3.py [1] 和 pyethereum [2]。就我目前的理解來說,兩者的差別在於 web3.py 主要是作為外部存取 Ethereum 的客戶端,也就是說 web3.py 函式庫本身不會成為區塊鏈節點,也不會進行區塊鏈同步,而是連接一個區塊鏈上的節點,把區塊鏈當成像是外部資料庫一樣取用而已;而 pyethereum 則比較像是 geth 那樣,是用來把自己做成一個區塊鏈節點,會正常進行區塊同步,也可以作為礦工開始挖礦。

在本篇當中,因為是想要一個輕量級的客戶端來與區塊鏈互動,並不想要準備龐大的儲存空間來存放區塊鏈的資料,因此會以 web3.py 為主。

Microsoft Visual C++ 14.0 is required

參考資料
  1. Fix Python 3 on Windows error Microsoft Visual C++ 14.0 is required

在 Java 存取 Ethereum 區塊鏈:透過 ethereumj

嗯…標題寫是這樣寫啦,不過其實因為實驗到一半就終止了,因此這篇其實只是留下一點點紀錄而已,並不會真的有完整的範例和說明。

(書籤) Ethereum 的 light client protocol

在一般情況下,Ethereum 的客戶端都需要一定程度地下載區塊鏈上的資料,並在自己的本地端開始驗證、組成現在的狀態
能做的選項頂多也就是 full client 跟 fast sync 的差別。
不過在有 light Client [1] 的情況下就不同了,Light Client 的目的是避免同步 block 的需求,改為去問網路上的其他 client。
但至少到目前為止,light client 還不是一個完全準備好的協定,所以也不是所有 client 都能支援它(雖然說 geth 和 parity 都支援了)。

參考資料
  1. Light client protocol
  2. ethereumj - Add "light client" support

2018年8月23日 星期四

Java 中的 Bit 操作

簡要地紀錄結論,看起來在想要儲存大量的 Bit 資料時,使用 BitSet 或者 boolean[] 是比較好的選擇
其中 BitSet 好像比較節省記憶體(據說每個資料都消耗 1 bit)
但如果資料量不夠大的時候(長度數百萬以內),boolean[] 的 CPU 運算速度比較快。

參考資料
  1. Java 快速導覽 - 位元運算子
  2. java - how to create and manipulate a bit array with length of 10 million bits
  3. boolean[] vs. BitSet: Which is more efficient?

2018年5月21日 星期一

透過 Spring Data JPA 存取 DynamoDB

因為 Spring Data JPA 用來存取資料庫時很方便,然後 DynamoDB 又是屬於特別囉唆的東西,所以之前在研究 Spring Boot 時,就在想不知道 Spring 是否有支援 DynamoDB 的實作。很幸運地,社群真的有人做了 Spring Data JPA + DynamoDB [1-2] 造福大家!XD

2018年5月17日 星期四

在 GCP 上為 VM 設定防火牆

在雲端環境中,防火牆的概念其實跟傳統模式有點不同。傳統的防火牆概念是在作業系統上設定像是 iptables 等。但在雲端上,因為網路服務是由獨立的元件提供的,所以其實應該用 SdN(Software defined Network)的方式來思考這個問題。具體來說就是,網路相關的設定並不會在 VM 上設定,而是在 VM 外部設定,就像是真的有個牆放在 VM 前面這樣。

設定防火牆規則

在 GCP 中,網路服務的提供是由 VPC 來進行的,因此在設定時要先在「VPC networks」裡的「Firewall rules」新增防火牆規則。防火牆規則的內容中,最重要的在於這個規則要套用到哪些 VM,而決定套用對象的方式在於設定「Targets」。

Targets 有三種模式可以設定:

  1. All instances in the network
  2. Specified target tags
  3. Specified service account

如果想要簡單的話,可以設定成 1,也就是規則將套用到網路中所有的 VM。不過如果只想針對特定一些 VM 的話,用 2 比較合適。用 2 的模式時,會需要輸入對象的標籤名稱,假設我想要打開 22 port,所以我命名標籤叫做「allow-ssh」,代表只要 VM 有「allow-ssh」這個標籤,就要套用這條防火牆規則。

設定 VM 標籤

接下來是比較奇特的地方,在 VM 上要標剛剛寫的標籤。從「Compute Engine」進入「VM Instances」,然後編輯想要設定防火牆的 VM。編輯時,要注意要找的是「Network tags」(中文介面會寫「網路標籤」)而不是「Lables」(中文介面會寫「標籤」)……。因為剛剛在防火牆規則設定的標籤是「allow-ssh」,因此 VM 的 Network tags 裡也要設定相同的名字。設定完以後,儲存然後稍微等一下下,防火牆規則就會套上 VM 了。

2018年5月15日 星期二

Ethereum 基礎概念與原理

Ethereum 是一種分散式帳本的技術,雖然說大家更熟知的是「以太幣」這個虛擬貨幣~。不過這裡會嘗試從系統工程師的角度來看帶這個技術。

這篇文章大概會寫得有點雜亂,因為這主要是要紀錄一些本來我自己不太清楚的問題。如果需要比較完整、有條理的說明,推薦可以認真看看 [1]。

2018年5月7日 星期一

AWS DynamoDB SDK v2 基礎使用(四):讀取資料

在 DynamoDB 中,讀取被分成 Query 和 Scan 兩種行為
兩種行為的差異,主要來自於存取的範圍是否侷限於同一個 Partition。
這其實在之前(好久以前了呀….XD)的文章中有提到過,概念上可以當成一個 Partition 就是一台主機
在寫入資料時,作為 Partition Key 的值會決定資料會被存放在哪一台主機。
而讀取資料時,使用 Query 是在特定一台主機上讀取資料,而使用 Scan 則會在所有主機上讀取資料。

2018年4月24日 星期二

Logback 的 Log 篩選設定

平常比較容易遇到的有幾種案例:

  1. 我想要 logback 輸出所有的 log,但特定某些 package 想要隱藏 DEBUG 和 TRACE
  2. 我想要 logback 只輸出 INFO 以上的 log,但特定某些 package 想要輸出所有 log
  3. 我想要 logback 只輸出 INFO 以上的 log,但特定某些 package 想要輸出所有 log,而且某個 package 的 INFO 以上 log 要輸出到別的 appender

之前開發時,大多用到的是第一種,但偶而想要第二和第三種時,花了不少時間才調整出來
最後發現一開始對設定的認知其實有點不太正確。

2018年4月11日 星期三

Spring Data JPA 的 JOIN 操作

其實在 Spring 上要做 JOIN,還挺麻煩的…
如果可以的話,我覺得能不要做就不要做比較好 XD

不過真的需要的時候,如果是需要 SELECT 時做 JOIN,推薦可以參考 [1-2] 的說明。
實務應用的話,假設以 logback 輸出到 SQL Server 的格式作為範例
想要一次取得整個 log 包含相關的 property 和 stack trace,以下的 Entity 範例是能夠套用。

logback 輸出 SQL Server 的 schema

schema 可以參考 [3],以下為 schema 的內容:

CREATE TABLE logging_event 
  ( 
    timestmp          DECIMAL(20) NOT NULL,
   	formatted_message VARCHAR(4000) NOT NULL,
    logger_name       VARCHAR(254) NOT NULL,
    level_string      VARCHAR(254) NOT NULL,
    thread_name       VARCHAR(254),
    reference_flag    SMALLINT,
    arg0              VARCHAR(254),
    arg1              VARCHAR(254),
    arg2              VARCHAR(254),
    arg3              VARCHAR(254),
    caller_filename   VARCHAR(254) NOT NULL,
    caller_class      VARCHAR(254) NOT NULL,
    caller_method     VARCHAR(254) NOT NULL,
    caller_line       CHAR(4) NOT NULL,
    event_id          DECIMAL(40) NOT NULL identity,
    PRIMARY KEY(event_id) 
  ) 

CREATE TABLE logging_event_property 
  ( 
    event_id          DECIMAL(40) NOT NULL, 
    mapped_key        VARCHAR(254) NOT NULL, 
    mapped_value      VARCHAR(1024), 
    PRIMARY KEY(event_id, mapped_key), 
    FOREIGN KEY (event_id) REFERENCES logging_event(event_id) 
  ) 

CREATE TABLE logging_event_exception 
  ( 
    event_id         DECIMAL(40) NOT NULL, 
    i                SMALLINT NOT NULL, 
    trace_line       VARCHAR(254) NOT NULL, 
    PRIMARY KEY(event_id, i), 
    FOREIGN KEY (event_id) REFERENCES logging_event(event_id) 
  )
Entity

假設我的 Entity 物件名字是 Activity、ActivityProperty、ActivityStackTrace,分別定義如下:

Activity

@Entity(name = "logging_event")
public class Activity implements Serializable {
  @Id
  @Column(name = "event_id")
  private Long eventId;
  
  @Column(name = "timestmp")
  private Long timestmp;
  
  @Column(name = "formatted_message")
  private String message;
  
  @Column(name = "logger_name")
  private String logger;
  
  @Column(name = "level_string")
  private String level;
  
  @Column(name = "thread_name")
  private String thread;
  
  @Column(name = "reference_flag")
  private Integer reference;
  
  @Column(name = "arg0")
  private String arg0;
  
  @Column(name = "arg1")
  private String arg1;
  
  @Column(name = "arg2")
  private String arg2;
  
  @Column(name = "arg3")
  private String arg3;
  
  @Column(name = "caller_filename")
  private String callerFile;
  
  @Column(name = "caller_class")
  private String callerClass;
  
  @Column(name = "caller_method")
  private String callerMethod;
  
  @Column(name = "caller_line")
  private String callerLine;
  
  @OneToMany(
      mappedBy = "eventId",
      cascade = CascadeType.ALL,
      fetch = FetchType.EAGER)
  private List<ActivityProperty> properties;
  
  @OneToMany(cascade = CascadeType.ALL)
  @JoinColumn(name = "event_id", referencedColumnName = "event_id")
  @LazyCollection(LazyCollectionOption.FALSE)
  private List<ActivityStackTrace> stackTraces;
}

ActivityProperty

@Entity(name = "logging_event_property")
public class ActivityProperty implements Serializable {
  private static final long serialVersionUID = -6532428503805543364L;

  @Id
  @Column(name = "event_id")
  private Long eventId;
  
  @Column(name = "mapped_key")
  private String key;
  
  @Column(name = "mapped_value")
  private String value;
}

ActivityStackTrace

@Entity(name = "logging_event_exception")
public class ActivityStackTrace implements Serializable {
  private static final long serialVersionUID = -50856985039937262L;

  @EmbeddedId
  private ActivityStackTraceId id;
  
  @Column(name = "trace_line")
  private String line;
}

ActivityStackTraceId

@Embeddable
public class ActivityStackTraceId implements Serializable {
  private static final long serialVersionUID = -4496556483758827756L;

  @Column(name = "event_id")
  private Long eventId;
  
  @Column(name = "i")
  private Integer i;
}

其中在 Activity 要連結 ActivityProperty 和 ActivityStackTrace 時,都是以 @OneToMany 來標注
用來表示一個 Activity 可以有多個 ActivityProperty 和 ActivityStackTrace。
此外,由於 ActivityStackTrace 並非是單一 ID,而是 Composite Primary Key 的形式
因此要利用 @Embeddable來組合。這部份可以參考 [4]。
同時,使用了 @Embeddable 之後,如果 JOIN 操作依然使用 mappedBy 的話,會出現 [5] 提到的錯誤
目前其實還沒有搞很懂這個錯誤是什麼意思,不過姑且使用 [5] 的作法,改成用 LazyCollection 可以解決。
未來如果有把問題搞懂的話,再回來追加補充了 @@a

除此之外,還得稍微注意一下,上述的 JOIN 寫法,有可能導致 [6] 描述的問題
也就是當要做資料刪除時,Hibernate 產生的 SQL Statement 會用很沒效率的方式在刪除關聯
而且某些狀況下有可能會刪除沒有預期要刪除的資料。

參考資料
  1. JPA,在@OneToMany里加入mappedBy属性
  2. hibernate基于注解的维护权反转:@OneToMany(mappedBy=)
  3. mssql.sql
  4. The best way to map a Composite Primary Key with JPA and Hibernate
  5. Hibernate cannot simultaneously fetch multiple bags
  6. Why you should avoid CascadeType.REMOVE for to-many associations and what to do instead
  7. @JoinColumn 详解

QuerySyntaxException: Path expected for join

參考資料
  1. HQL ERROR: Path expected for join

2018年3月14日 星期三

在 eclipse 使用 AutoValue

AutoValue 是個可以方便用來產生 POJO 程式碼的套件
網路上有蠻多教學文的~這裡暫時先不紀錄 XD

在 eclipse 上使用 AutoValue 時,會遇到本來應該自動產生的 AutoValue_<CLASS_NAME> 一直說找不到
而原因是在 eclipse 上預設是不會自動進行 annotation processing
因此要讓 AutoValue 可以正常在 eclipse 上運作的話,必須先在 eclipse 安裝 m2e-apt 套件 [2]。

具體來說,就是在 eclipse 上打開 Eclipse MarketPlace(Help –> Eclipse MarketPlace…),然後搜尋 m2e-apt 來安裝。
安裝完以後,在 Window –> Preferences –> Maven –> Annotation Processing 裡的最上面那個區塊
改成選擇 Automatically configure JDT APT 的選項。

之後再做一次 Maven Update 讓專案重新編譯就可以了。

參考資料
  1. Maven AutoValue Errors
  2. m2e-apt

2018年3月9日 星期五

(書籤) Java 繁體與簡體轉換

雖然繁體和簡體的轉換有一些開源專案了,但他們大多都加了一個額外的功能:詞彙代換
例如「database」臺灣稱為「資料庫」,中國則稱為「数据库」
在有些狀況,自動做這個轉換很好,但有時候其實我不想要它幫我轉換……Orz

於是就找了點資料,大體上好像都是自己實作,可能也是因為這問題難度太低,不值得做成一個開源專案…..??
不過在 CSDN 上看到有人 [1] 很好心地做了看起來比較可靠的文字比對,並整理出共 2,579 個繁體和簡體不同字的對照。

裡面有完整的程式碼,有需要的人可以直接參閱 [1]。

當然 [1] 的實作方法很土法煉鋼,依據需求是能夠做些調校的,不過那就看各自的需求自己解決吧!XD

不過需要注意的是,因為這個實作單純只看每個字而已,所以如果是繁轉簡後再簡轉繁,跑出來的結果有可能跟原始字串不同
例如「限制」轉成簡體會是「限制」,但再轉回繁體會變成「限製」。
這是因為繁體對簡體有多對一的問題,實際上得依照詞彙決定該用哪個字,才能更精準一點地轉換。

題外話,[1] 整理出來的數據蠻有意思的:

  1. 全部的漢字有 20,881 個。
  2. 繁簡不同字的有 2,579 個。
  3. 繁轉簡有多對一現象的只有 44 個。
  4. 另外有 3 個簡轉繁時有多對一現象。
參考資料
  1. Java 汉字繁体转简体

2018年3月6日 星期二

使用 Jest 搜尋 Elasticsearch

Elasticsearch 官方本來是有提供官方的 SDK 可以用來操作 Elasticsearch
不過…官方版的 SDK 在存取 Elasticsearch 時,是把自己當作 Elasticsearch Cluster 的一員來看待
因此會有包括 heartbeat 等行為在 SDK 裡自動發生。
理論上這麼做的好處是,SDK 可以看見整個 Cluster 的狀態,因此可以比較妥善地選擇存取的節點
不過代價就是維持 Elasticsearch 連線所需要的資源更多、連線速度感覺好像變慢
此外,對於跑在 AWS Lambda 的程式來說,有不少潛在的缺點。
在 Elasticsearch 官方的描述 [1] 中,有建議了可以考慮使用 Jest [2],因此就來試試它了。

2018年2月6日 星期二

Logback 輸出 Log 到 CloudWatch

本來沒有特別使用 CloudWatch 的習慣
不過應用程式放在 VM 裡,如果不控管的話,Log 總有一天會把 VM 硬碟塞爆
而如果去設定控制大小,則又會有關鍵 Log 可能被洗掉的問題。
剛好最近寫不少 AWS Lambda 的程式,覺得 Log 丟去 CloudWatch 其實也還蠻方便的 XD
就找了一下該怎麼做這件事。

2018年1月11日 星期四

(暫存) Python Dependency Management

參考資料

  1. Maven equivalent for python
  2. Python深入:Distutils发布Python模块

(暫存) AWS Step Function

名詞
  • terminal state:代表會讓流程結束的 State。具體有三種表現方式:
    1. State 具有 “End”: true 這個屬性。
    2. State 的種類是 “Type”: “Succeed” 或者 “Type”: “Fail”
訊息傳遞

在 Step Function 的每個 State 之間,預設狀況是呼叫一個 Task 時,Task 的回覆會成為 State 的 Output
然後原因是因為預設的 OutputPath 是 ‘$’。這裡 OutputPath 代表的是 Task 回覆的東西,要覆蓋到哪裡去。
如果 OutputPath 設為 null,表示回覆的內容不覆蓋,此時 State 的 Output 就會是 State 的 Input。
但如果 OutputPath 設定為像是 ‘$.result’ 的話,那麼 State 的 Output 就會是原本的 Input 再加上 result 這個 key。

參考資料
  1. Iterating with AWS Step Functions
  2. Forum: AWS Step Functions >Thread: Dynamic number of parallel tasks
  3. Amazon States Language

2018年1月10日 星期三

Python 的時間處理

字串轉時間

假設字串是「Wed, 10 Jan 2018 08:09:13 +0000」,可以使用這樣的 Pattern 來解析:

from datetime import datetime

time_text = 'Wed, 10 Jan 2018 08:09:13 +0000'
datetime.strptime(time_text, '%a, %d %b %Y %H:%M:%S %z')

其中 Pattern 的寫法可以參考官方的文件 [1]。

取得帶有時區資訊的現在時間
需要特別這麼做的原因,是因為如果是直接使用 datetime.now() 的話,得到的時間是沒有時區的
這在需要做時間比較時有可能會有問題,尤其在要比較的時間本身就有時區資訊的話,Python 會回傳錯誤訊息。

from datetime import datetime, timezone

datetime.now(timezone.utc)
計算時間
取得三小時前的時間

from datetime import datetime, timedelta, timezone

datetime.now(timezone.utc) - timedelta(hours=3)
參考資料
  1. strptime
  2. Python get current time in right timezone [duplicate]

2018年1月9日 星期二

AWS DynamoDB SDK v2 基礎使用(三):寫入資料

DynamoDB 不得不說,其實表達的格式相當囉唆~
所以想要存取 DynamoDB,無論如何程式碼都會寫得有點冗長。
而其中因為 Java 又是格式嚴謹的語言,於是又比別的語言再更囉唆一些……。

2018年1月3日 星期三

Python 的日誌

Python 內建就有個 logging 的套件 [1],可以使用設定檔來控制 log 的輸出。
不過實務上有一點小地方需要注意。