Skip to content

Commit ebf4eea

Browse files
committed
linting, sigh
1 parent 03dcbf6 commit ebf4eea

1 file changed

Lines changed: 89 additions & 43 deletions

File tree

ctorm/granule-md-db-loader/granule_md_db_loader.py

Lines changed: 89 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
from botocore.config import Config
1212

1313
# Configure logging
14-
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
14+
fmt = "%(asctime)s [%(levelname)s] %(message)s"
15+
logging.basicConfig(level=logging.INFO, format=fmt)
1516
logger = logging.getLogger(__name__)
1617

1718

@@ -34,7 +35,8 @@ def limit(self, pk):
3435
self.history[pk] = [t for t in self.history[pk] if now - t < 1.0]
3536

3637
if len(self.history[pk]) >= self.max_rate:
37-
# Calculate sleep duration to let the oldest request roll off the 1-second window
38+
# Calculate sleep duration to let the oldest request roll
39+
# off the 1-second window
3840
sleep_time = 1.0 - (now - self.history[pk][0])
3941
if sleep_time > 0:
4042
time.sleep(sleep_time)
@@ -44,6 +46,53 @@ def limit(self, pk):
4446
self.history[pk].append(now)
4547

4648

49+
def handle_file(
50+
local_path,
51+
table,
52+
rate_limiter: PartitionRateLimiter,
53+
records_in_file,
54+
total_records,
55+
):
56+
with gzip.open(local_path, "rt", encoding="utf-8") as f:
57+
with table.batch_writer() as batch:
58+
for line in f:
59+
line = line.strip()
60+
if not line:
61+
continue
62+
63+
try:
64+
# Convert floats/doubles to Decimal for
65+
# DynamoDB compatibility
66+
item = json.loads(line, parse_float=Decimal)
67+
except Exception as e:
68+
logger.error(f"Failed to parse JSON line: {e}")
69+
continue
70+
71+
# Add/modify fields if needed
72+
newdate = datetime.datetime.utcnow().isoformat() + "Z"
73+
item["imported_at"] = newdate
74+
75+
# Ensure partition and sort keys are present
76+
pk = item.get("pk")
77+
sk = item.get("sk")
78+
if not pk or not sk:
79+
logger.warning(
80+
"Skipping record missing pk/sk: %s",
81+
item.get('granule_id'),
82+
)
83+
84+
continue
85+
86+
# Apply dynamic rate limit based on the partition key
87+
rate_limiter.limit(pk)
88+
89+
# Batch insert into DynamoDB
90+
batch.put_item(Item=item)
91+
records_in_file += 1
92+
total_records += 1
93+
return records_in_file, total_records
94+
95+
4796
def main():
4897
bucket_name = os.environ.get("CTORM_BUCKET", "ctorm-scratch")
4998
table_name = os.environ.get("TABLE_NAME")
@@ -55,25 +104,32 @@ def main():
55104

56105
s3 = boto3.client("s3")
57106

58-
# Configure boto3 with more aggressive retries to gracefully handle scale peaks
107+
# Configure boto3 with more aggressive retries to gracefully
108+
# handle scale peaks
59109
retry_config = Config(
60110
retries={
61111
"max_attempts": 10,
62-
"mode": "standard"
112+
"mode": "standard",
63113
}
64114
)
65115
dynamodb = boto3.resource("dynamodb", config=retry_config)
66-
table = dynamodb.Table(table_name)
116+
dyndb_table = dynamodb.Table(table_name)
67117

68-
logger.info(f"Starting import from s3://{bucket_name}/{prefix} into DynamoDB table {table_name}")
118+
logger.info(
119+
"Starting import from s3://%s/%s into DynamoDB table %s",
120+
bucket_name,
121+
prefix,
122+
table_name,
123+
)
69124

70125
paginator = s3.get_paginator("list_objects_v2")
71126
pages = paginator.paginate(Bucket=bucket_name, Prefix=prefix)
72127

73128
total_files = 0
74129
total_records = 0
75130

76-
# Initialize partition-level rate limiter set to a safe threshold (850 writes/sec per pk)
131+
# Initialize partition-level rate limiter set to a safe
132+
# threshold (850 writes/sec per pk)
77133
rate_limiter = PartitionRateLimiter(max_rate_per_sec=850)
78134

79135
# Walk through the bucket objects
@@ -94,52 +150,42 @@ def main():
94150
try:
95151
s3.download_file(bucket_name, key, local_path)
96152
except Exception as e:
97-
logger.error(f"Failed to download s3://{bucket_name}/{key}: {e}")
153+
logger.error(
154+
"Failed to download s3://{%s}/%s: %s",
155+
bucket_name,
156+
key,
157+
e,
158+
)
98159
continue
99160

100161
# Open, decompress and parse
101162
records_in_file = 0
102163
try:
103-
with gzip.open(local_path, "rt", encoding="utf-8") as f:
104-
with table.batch_writer() as batch:
105-
for line in f:
106-
line = line.strip()
107-
if not line:
108-
continue
109-
110-
try:
111-
# Convert floats/doubles to Decimal for DynamoDB compatibility
112-
item = json.loads(line, parse_float=Decimal)
113-
except Exception as e:
114-
logger.error(f"Failed to parse JSON line: {e}")
115-
continue
116-
117-
# Add/modify fields if needed
118-
item["imported_at"] = datetime.datetime.utcnow().isoformat() + "Z"
119-
120-
# Ensure partition and sort keys are present
121-
pk = item.get("pk")
122-
sk = item.get("sk")
123-
if not pk or not sk:
124-
logger.warning(f"Skipping record missing pk/sk: {item.get('granule_id')}")
125-
continue
126-
127-
# Apply dynamic rate limit based on the partition key
128-
rate_limiter.limit(pk)
129-
130-
# Batch insert into DynamoDB
131-
batch.put_item(Item=item)
132-
records_in_file += 1
133-
total_records += 1
134-
135-
logger.info(f"Successfully imported {records_in_file} records from {key}")
164+
records_in_file, total_records = handle_file(
165+
local_path,
166+
dyndb_table,
167+
rate_limiter,
168+
records_in_file,
169+
total_records
170+
)
171+
172+
logger.info(
173+
"Successfully imported %s records from %s",
174+
records_in_file,
175+
key,
176+
177+
)
136178
except Exception as e:
137-
logger.error(f"Error processing file {key}: {e}")
179+
logger.error("Error processing file %s: %s", key, e)
138180
finally:
139181
if os.path.exists(local_path):
140182
os.remove(local_path)
141183

142-
logger.info(f"Import complete. Processed {total_files} files, imported {total_records} total records.")
184+
logger.info(
185+
"Import complete. Processed %s files, imported %s total records.",
186+
total_files,
187+
total_records,
188+
)
143189

144190

145191
if __name__ == "__main__":

0 commit comments

Comments
 (0)