Setup Lambda migrate & sync AWS DynamoDB to new table

AWS DynamoDB is a good persistence solution for a specific solution. However, it’s not for a growing and changing application that could need new indexes and queries for its ever expanding features at any time. At this moment it is where the flexibility and speed of a relational database really shined through.

Now, a DynamoDB table with Consumers Preferences data urgently needs to update:

  • RENAME one EXISTING attribute
  • ADD a new attribute
  • SET a value in the new attribute for ALL EXISTING items in DynamoDB’s new table

AWS DynamoDB Table

AWS lambda function plays handy here to migrate data, and sync newly inserted, modified / updated, deleted items between existing and new DynamoDB tables.

  • Create new DynamoDB table
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
$ aws dynamodb create-table \
--table-name userpreferences-ptest-02-USER_PREFERENCESV2 \
--attribute-definitions AttributeName=id,AttributeType=S AttributeName=preferenceType,AttributeType=S \
--key-schema AttributeName=id,KeyType=HASH AttributeName=preferenceType,KeyType=RANGE \
--provisioned-throughput ReadCapacityUnits=100,WriteCapacityUnits=100

{
"TableDescription": {
"TableArn": "arn:aws:dynamodb:ap-southeast-2:123456789012:table/userpreferences-ptest-02-USER_PREFERENCESV2",
"AttributeDefinitions": [
{
"AttributeName": "id",
"AttributeType": "S"
},
{
"AttributeName": "preferenceType",
"AttributeType": "S"
}
],
"ProvisionedThroughput": {
"NumberOfDecreasesToday": 0,
"WriteCapacityUnits": 100,
"ReadCapacityUnits": 100
},
"TableSizeBytes": 0,
"TableName": "userpreferences-ptest-02-USER_PREFERENCESV2",
"TableStatus": "CREATING",
"TableId": "d116efdc-1234-5678-90ab-011de3e124fe",
"KeySchema": [
{
"KeyType": "HASH",
"AttributeName": "id"
},
{
"KeyType": "RANGE",
"AttributeName": "preferenceType"
}
],
"ItemCount": 0,
"CreationDateTime": 1540273906.1059999
}
}

Migrate Data

  • Create Migrate Data Lambda function

AWS DynamoDB Lambda Migrate

Increase Memory and Runtime Timeout https://docs.aws.amazon.com/lambda/latest/dg/limits.html in case of execution pre-maturely ended without finishing the migration. Furthermore, in case of overcharging DynamoDB due to its limits https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html add time delay in Lambda function.

migrate.js

  • Add AWS DynamoDB Lambda execution role

AWS DynamoDB Lambda Execution Role

userpreferences-ptest-02-migrateRole

  • Create a simple test event that can kick off function
1
2
3
4
5
{
"key1": "value1",
"key2": "value2",
"key3": "value3"
}

Trigger run the function. Should see the data migrated from existing DynamoDB table into new table.

Log can be found at AWS CloudWatch Log Groups /aws/lambda/userpreferences-ptest-02-migrate

Sync Data

  • Enable Stream on the existing DynamoDB table

AWS DynamoDB Stream Enabled

  • Add a new trigger for DynamoDB table

AWS DynamoDB Triggers

  • Create a new Lambda function linked to trigger

AWS DynamoDB Lambda Sync

sync.js

  • Trigger Testing

AWS Lambda built-in test can test trigger:

AWS DynamoDB Lambda Test Event

  • Logging

Lambda function log can be found on AWS CloudWatch Log Groups /aws/lambda/userpreferences-ptest-02-sync

AWS DynamoDB CloudWatch Logging

Counter Data

This Lambda function can count the number of items in DynamoDB table.

counter.js

Async call, callback and Non-blocking, it’s very hard implement so in every applications. In addition, reject promises or async functions, don’t handle them with a catch, NodeJS will raise a warning. In a large complex applications with lots of async, having a single unhandled promise or await function terminate NodeJS, or have to handle them with try and catch in every place (spaghetti code again?) would be very bad.

An example of AWS DynamoDB error:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2018-11-14T02:20:50.742Z	715f18fb-e7b3-11e8-b5c4-d75f9089dd50	Error thrown: { ProvisionedThroughputExceededException: The level of configured provisioned throughput for the table was exceeded. Consider increasing your provisioning level with the UpdateTable API.
at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:48:27)
at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)
at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)
at Request.<anonymous> (/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)
at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:115:18)
message: 'The level of configured provisioned throughput for the table was exceeded. Consider increasing your provisioning level with the UpdateTable API.',
code: 'ProvisionedThroughputExceededException',
time: 2018-11-14T02:20:50.687Z,
requestId: 'C38MODOISAJEGTVPI2ISOPFGDBVV4KQNSO5AEMVJF66Q9ASUAAJG',
statusCode: 400,
retryable: true }

AWS example doesn’t throw the error in the catch block, it returns error instead, so any errors end up in the catch block. And return promises early and use Promise.all() method.

References

Apple Designs That Inspire / 吐槽苹果

列举一下我认为的苹果产品设计的经典。我并不是苹果的粉丝,也从来没有拥有过任何一代 iPhone 产品,from first generation iPhone, to latest iPhone XS。

iPhone Family

经典的 iPhone 5 / 5s

iPhone 5 / 5s

适合单手操作,体重适中,不打滑,有握持感。

新 iPhone 早已没有了新鲜感。全面屏,无线充电,双卡双待,屏下指纹识别,前后双屏 … 这些都已不再成为苹果的专利。

手机设计还是有很多潜力开发。还没走到尽头。In other words, 手机是现在最具创新和有最多创新的产品了。但苹果现在已经变得保守,中庸,不思进取了。

BTW,耳机 maybe 下一个智能产品竞争领域。Headphones 已经成为手机以外第二个人手必备的设备了。

iPad Mini 2 / 3 / 4

这是我在 October 23, 2012,the first generation iPad Mini was announced 时写的评论:

“It takes 30 months and 4 generatons since first release of iPad on April 3rd 2010, Apple finally gets the right size, right weight, right price, right design, right OS, right applications, right market niche, right balanced, almost no annoying public complainted issues, nearly all bugs been fixed iPad delivered”

iPad Mini 2 使用上 Retina Display. 至今仍然是轻便的不行,仍然流畅的不行。

新的“全”面屏 iPad Pro 本月要发布了。不明白“全”面屏在大屏幕设备上的意义。个人还是喜欢现在的 iPad pro 10.5. “全”面屏 iPad Pro 追求逼格,Bigger Than Bigger,牺牲掉 home button,少了一“键”钟情。

Why the hell MacBook has removed sleep light / 呼吸灯? Think about it after you have a look Transformers Mac light:

信仰灯

为甚 turn off 信仰灯,信仰的灯塔?有多少用户会在乎多费那么一点点用电。留下的只是深深的执念,蛋蛋的忧伤?

MagSafe

Magsafe 磁吸充电接口一直被认为是饱含创新和智慧设计。论安全性与便捷性还有什么比 MagSafe 做的更好?

Mac Mini

Why small is beautiful? 看看 Mac Mini 的结构。

Mac Mini structure

能把一个功能完整的 PC 主机,放进如此狭小的空间内,功耗低又安静,除了 brilliant 还能用什么来形容?

Mac Mini 已经好长时间没有更新换代。不知道苹果是否在考虑砍掉这个产品。

Serenity

近几年苹果的新产品设计是感觉在吃老本,going downhill. 好的设计没有继承发扬,反而在做减法被一一去掉。新产品亮相后总感觉缺少点什么。也许是一种精神,也许是一颗灵魂。

A Python script which implements Mantua Cipher

Run output from Console:

1
2
3
4
5
6
7
8
9
10
11
$ PycharmProjects/cipher/venv/bin/python PycharmProjects/cipher/src/cipher.py
[ 60 31 53 33 33 53 23 ] : blossom
[ 60 55 73 66 66 73 23 ] : blossom
[ 20 37 12 0 0 12 23 ] : blossom
[ 60 37 82 14 14 82 89 ] : blossom
[ 20 31 82 95 95 82 89 ] : blossom
[ 60 36 90 0 0 90 23 ] : blossom
[ 20 37 90 94 94 90 23 ] : blossom
[ 20 55 90 94 94 90 89 ] : blossom
[ 20 36 97 94 94 97 89 ] : blossom
[ 60 36 82 0 0 82 23 ] : blossom

Step by step resetting Bluetooth on Mac OS

Latest Mac OS High Sierra version 10.13.6.

  • Open Terminal and login as user “root”:
1
# rm /Library/Preferences/com.apple.Bluetooth.plist
  • Reset the Bluetooth Module with Option + Shift + click on bluetooth icon in taskbar. Click on Debug -> Reset the Bluetooth Module

Reset Bluetooth on Mac OS

Assumptions and Conditional Test execution, ignoring in JUnit

Sometime you want to ignore some test depends on environment settings. Now both JUnit 4 and JUnit 5 support the concept of assumptions.

Unit Test like this:

1
2
3
4
5
6
7
@Test
public void testRun() {

Assume.assumeTrue(BooleanUtils.toBoolean(System.getProperty("runtest")));

// Rest of testcase
}

With Gradle, pass in parameter like this:

1
$ gradle test -Pruntest=false

References

Making VSCode like IntelliJ after line commented the cursor automatically moved to next line

Want to make VSCode key bindings as closed as IntelliJ key bindings like.

Firstly, install VSCode extension macros.

macros

Open Code -> Preferences -> Settings. Add following configuration into User Settings.

1
2
3
4
5
6
"macros": {
"commentLine": [
"editor.action.commentLine",
"cursorDown"
]
}

User Settings

Open Code -> Preferences -> Keyboard Shortcuts. Add following configuration into keybindings.json file.

1
2
3
4
5
6
7
8
// Place your key bindings in this file to overwrite the defaults
[
{
"key": "cmd+/",
"command": "macros.commentLine",
"when": "editorTextFocus && !editorReadonly"
}
]

keybindings.json

That’s newly added Toggle Line Comment looks like after the change:

Toggle Line Comment

Take over Mac OS X Bluetooth Control

Bluetooth on Mac OS X

Quite annoying when Bluetooth on Mac OS X is off, you can’t turn it on manually via Systme Preferences interface. Now you can install blueutil from https://github.com/toy/blueutil to solve this issue.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
igloo:cheatsheets root# blueutil --help
blueutil v2.1.0

Usage:
blueutil [options]

Without options outputs current state

-p, --power output power state as 1 or 0
-p, --power STATE set power state
-d, --discoverable output discoverable state as 1 or 0
-d, --discoverable STATE set discoverable state

-h, --help this help
-v, --version show version

STATE can be one of: 1, on, 0, off, toggle

Firstly, turn off Bluetooth service via command line:

1
2
igloo:cheatsheets root# blueutil -p 0
igloo:cheatsheets root# blueutil -d 0

Then turn on Bluetooth service via command line:

1
2
igloo:cheatsheets root# blueutil -d 1
igloo:cheatsheets root# blueutil -p 1