- Đăng vào
Database với Google sheets
- Tác giả
- Name
- Quang Mau
- @qmauvnt
Mục lục
TL;DR
- Dùng Google spreadsheet làm cơ sở dữ liệu thay cho DynamoDB trong bài viết Crawl dữ liệu tỷ giá hối đoái với AWS Lambda và DynamoDB (Over engineer version)
- Bạn có thể truy cập "production database" của ứng dụng này tại google sheet này
Yêu cầu
Vẫn là yêu cầu lấy dữ liệu tỷ giá hối đoái của 3 ngân hàng Việt Nam như đã trình bày ở bài viết trước. Dù không được trả tiền nhưng khi nghĩ đến việc mẹ của cháu tôi lọ mọ download file csv từ API gateway tôi vẫn thấy hơi cắn rứt. Giúp người thì giúp cho chót, thêm nữa tháng sau cháu mới đi mẫu giáo nên tôi đành làm phần giao diện friendly với người dùng hơn.
💡 Và đây là diagram của hệ thống mới
Google sheets là giải pháp rất tốt vì nó đáp ứng được 2 yêu cầu:
- Thân thiện với người dùng (chị tôi)
- Có thể làm database 🤥
- Google sheets không có tính mở rộng (scalability)
Chỉ có thể lưu trữ 5 triệu ô tính, không có truy vấn hoặc truy vấn join và có giới hạn số lần gọi API.
Triển khai
Google sheets
- Tạo google sheets mới. Lưu lại sheet id của bảng tính.
- Tạo một project mới trên GCP
- Enable google sheet api cho project
Crawler cần sử dụng api spreadsheet append nên không thể sử dụng kiểu xác thực với API key, lựa chọn đơn giản nhất là sử dụng service account.
Tạo service account và tạo key cho service account
- Save key dưới tên file credentials.json ở trong thư mục lambda function
- Chia sẻ quyền sửa trang tính với email của service account
Sam template & Lambda function
- Sửa lại file template, xoá bỏ những resource không cần dùng tới như
- Get CSV function
- HTTP API
- DynamoDB
- Thêm các biến môi trường cho hàm Crawler
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
currency-crawler
Sample SAM Template for currency-crawler
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 300
Environment:
Variables:
SPREADSHEET_ID: '1nzKN3NSTh_AVQlSOm5Zv4CQZlejkPpHw3FkOm6T1zio'
RANGE_NAME: 'A1:H1'
VALUE_INPUT_OPTION: 'USER_ENTERED'
Resources:
CurrencyCrawlFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: currency/
Handler: app.crawl
Runtime: python3.9
Architectures:
- x86_64
Events:
InvocationLevel:
Type: Schedule
Properties:
Schedule: cron(0 11 ? * MON-FRI *) # All scheduled events use UTC+0 time zone
Outputs:
CurrencyCrawlFunction:
Description: "Currency Crawler Lambda Function ARN"
Value: !GetAtt CurrencyCrawlFunction.Arn
CurrencyCrawlFunctionIamRole:
Description: "Implicit IAM Role created for Currency Crawler function"
Value: !GetAtt CurrencyCrawlFunctionRole.Arn
- Sửa lại hàm crawler của các banks, chuyển từ kiểu decimal -> float cho các tỷ giá (DynamoDB chỉ nhận kiểu Decimal còn google sheet thì không)
from datetime import date
from mbb import get_record as get_mbb_record
from scb import get_record as get_scb_record
from bidv import get_record as get_bidv_record
import json
from config import logger
from utils import append_to_db, format_record
def crawl(event, context):
try:
requested_date_str = date.today().strftime("%d/%m/%Y")
mbb_record = get_mbb_record(requested_date_str)
append_to_db(format_record(mbb_record))
bidv_record = get_bidv_record(requested_date_str)
append_to_db(format_record(bidv_record))
scb_record = get_scb_record(requested_date_str)
append_to_db(format_record(scb_record))
logger.info("Inserted to Google sheet")
except Exception as e:
logger.error(e)
raise e
return {
"statusCode": 200,
"body": json.dumps({
"message": "Done! Currencies data imported",
}),
}
record[currency] = Decimal(ck) -> record[currency] = float(ck)
- Xoá các hàm tương tác với DynamoDB, thay vào đó là các hàm append dữ liệu vào google sheet
requests
bs4
google-api-python-client
google-auth-httplib2
google-auth-oauthlib
import os
import google.auth
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = './credentials.json'
SPREADSHEET_ID = os.environ.get('SPREADSHEET_ID')
RANGE_NAME = os.environ.get('RANGE_NAME')
VALUE_INPUT_OPTION = os.environ.get('VALUE_INPUT_OPTION')
def append_to_db(values):
creds, _ = google.auth.default()
try:
service = build('sheets', 'v4', credentials=creds)
# ["2022/03/17", "MBB", "23020", "25876", "198.31", "16962", "2996", "17169"]
body = {
'values': [values]
}
result = service.spreadsheets().values().append(
spreadsheetId=SPREADSHEET_ID, range=RANGE_NAME,
valueInputOption=VALUE_INPUT_OPTION, body=body).execute()
print(f"{(result.get('updates').get('updatedCells'))} cells appended.")
return result
except HttpError as error:
print(f"An error occurred: {error}")
return error
# date bank USD EUR JPY AUD HKD SGD
def format_record(record):
arr = []
arr.append(record['date'])
arr.append(record['bank'])
arr.append(record['USD'])
arr.append(record['EUR'])
arr.append(record['JPY'])
arr.append(record['AUD'])
arr.append(record['HKD'])
arr.append(record['SGD'])
return arr
Test & Validate & Build & Deploy
# test function
sam local invoke "CurrencyCrawlFunction" -e events/event.json
# validate SAM template
sam validate --profile vntechies --region ap-southeast-1
# build package
sam build
# deploy
sam deploy --guided --profile vntechies
Demo ở local bằng sam local invoke
Bằng việc loại bỏ DynamoDB, API gateway khỏi hệ thống, những việc cần hoàn thiện cũng được lược bỏ
Thứ mà tôi vẫn sẽ không làm vì tôi không được trả tiền cho việc này 😂- Xử lý lỗi cho các HTTP requests tới các site của banks đề phòng trường hợp bank nào đó bật maintainance mode, thay đổi giao diện, handle dead letter queue
Đánh index cho bảng Currency, sử dụng query thay vì scan để giảm chi phí (nếu phát sinh), sử dụng DynamoDB update expressions xử lý việc ghi đè dữ liệu nếu cóSử dụng Authentication cho các APIs- Headless browser trên Lambda
- Unit tests và integration tests, tạo các môi trường phát triển khác (dev, staging,...)
Handle file size limit từ Lambda (6MB). Cũng là lời nhắn nhủ với chị gái, đừng download dữ liệu > 12 tháng. 🙄
Vậy là cháu tôi có thêm thời gian chơi với mẹ, giải pháp cồng kềnh đã được thu gọn bớt, thân thiện hơn với người dùng cuối 🤟
Hãy để lại đánh giá, comment nếu bạn cảm thấy tutorial này hữu ích (hoặc vui) nhé! 😬
Reference
VNTechies Dev Blog
Kho tài nguyên mã nguồn mở với sứ mệnh đào tạo kiến thức, định hướng nghề nghiệp cho cộng đồng Cloud ☁️ DevOps 🚀
Tham gia group VNTechies - Cloud ☁️ / DevOps 🚀 nếu bạn muốn giao lưu với cộng đồng và cập nhật các thông tin mới nhất về Cloud và DevOps.
- Website: https://vntechies.dev
- Github repository: https://github.com/vntechies
- Facebook page: https://facebook.com/vntechies
Anh chị em hãy follow/ủng hộ VNTechies để cập nhật những thông tin mới nhất về Cloud và DevOps nhé!