Skip to content

Commit 922a531

Browse files
committed
refactor(staging): address review comments
- Use UUID instead of timestamp for GCS validate test key uniqueness - Handle empty prefix in GCS validate with TrimPrefix - Rename S3-specific names: s3TableFunctionBuilder → stagingTableFunctionBuilder, pushDataToS3ForSnapshot → pushDataToStagingForSnapshot, etc. - Rename s3AvroFileKey → stagingAvroFileKey - Restore panic handler in OCF write goroutine - Move bucket name fallback from dynamicconf back into staging.go caller - Restore PeerDBClickHouseAWSS3BucketName as simple lookup
1 parent 7069bf2 commit 922a531

4 files changed

Lines changed: 39 additions & 33 deletions

File tree

flow/connectors/clickhouse/avro_sync.go

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,21 @@ func NewClickHouseAvroSyncMethod(
3838
}
3939
}
4040

41-
func (s *ClickHouseAvroSyncMethod) s3TableFunctionBuilder(ctx context.Context, avroFilePath string) (string, error) {
41+
func (s *ClickHouseAvroSyncMethod) stagingTableFunctionBuilder(ctx context.Context, avroFilePath string) (string, error) {
4242
return s.staging.TableFunctionExpr(ctx, avroFilePath, "Avro")
4343
}
4444

4545
func (s *ClickHouseAvroSyncMethod) CopyStageToDestination(ctx context.Context, avroFile utils.AvroFile) error {
46-
s3TableFunction, err := s.s3TableFunctionBuilder(ctx, avroFile.FilePath)
46+
stagingTableFunction, err := s.stagingTableFunctionBuilder(ctx, avroFile.FilePath)
4747
if err != nil {
48-
s.logger.Error("failed to build S3 table function",
48+
s.logger.Error("failed to build staging table function",
4949
slog.String("avroFilePath", avroFile.FilePath),
5050
slog.Any("error", err))
51-
return fmt.Errorf("failed to build S3 table function: %w", err)
51+
return fmt.Errorf("failed to build staging table function: %w", err)
5252
}
5353

5454
query := fmt.Sprintf("INSERT INTO %s SELECT * FROM %s",
55-
peerdb_clickhouse.QuoteIdentifier(s.config.DestinationTableIdentifier), s3TableFunction)
55+
peerdb_clickhouse.QuoteIdentifier(s.config.DestinationTableIdentifier), stagingTableFunction)
5656
return s.exec(ctx, query)
5757
}
5858

@@ -116,7 +116,7 @@ func (s *ClickHouseAvroSyncMethod) SyncQRepRecords(
116116
numericTruncator := model.NewSnapshotTableNumericTruncator(dstTableName, schema.Fields)
117117

118118
columnNameAvroFieldMap := model.ConstructColumnNameAvroFieldMap(schema.Fields)
119-
avroFiles, totalRecords, err := s.pushDataToS3ForSnapshot(ctx, config, dstTableName, schema,
119+
avroFiles, totalRecords, err := s.pushDataToStagingForSnapshot(ctx, config, dstTableName, schema,
120120
columnNameAvroFieldMap, partition, stream, destTypeConversions, numericTruncator)
121121
if err != nil {
122122
s.logger.Error("failed to push data to S3",
@@ -125,7 +125,7 @@ func (s *ClickHouseAvroSyncMethod) SyncQRepRecords(
125125
return 0, nil, err
126126
}
127127

128-
if err := s.pushS3DataToClickHouseForSnapshot(
128+
if err := s.pushStagingDataToClickHouseForSnapshot(
129129
ctx, avroFiles, schema, columnNameAvroFieldMap, config); err != nil {
130130
s.logger.Error("failed to push data to ClickHouse",
131131
slog.String("dstTable", dstTableName),
@@ -142,7 +142,7 @@ func (s *ClickHouseAvroSyncMethod) SyncQRepRecords(
142142
return totalRecords, warnings, nil
143143
}
144144

145-
func (s *ClickHouseAvroSyncMethod) pushDataToS3ForSnapshot(
145+
func (s *ClickHouseAvroSyncMethod) pushDataToStagingForSnapshot(
146146
ctx context.Context,
147147
config *protos.QRepConfig,
148148
dstTableName string,
@@ -237,7 +237,7 @@ func (s *ClickHouseAvroSyncMethod) pushDataToS3ForSnapshot(
237237
return avroFiles, totalRecords, nil
238238
}
239239

240-
func (s *ClickHouseAvroSyncMethod) pushS3DataToClickHouseForSnapshot(
240+
func (s *ClickHouseAvroSyncMethod) pushStagingDataToClickHouseForSnapshot(
241241
ctx context.Context,
242242
avroFiles []utils.AvroFile,
243243
schema types.QRecordSchema,
@@ -277,24 +277,24 @@ func (s *ClickHouseAvroSyncMethod) pushS3DataToClickHouseForSnapshot(
277277

278278
for i := range numParts {
279279
// Get fresh credentials for each part
280-
s3TableFunction, err := s.s3TableFunctionBuilder(ctx, avroFile.FilePath)
280+
stagingTableFunction, err := s.stagingTableFunctionBuilder(ctx, avroFile.FilePath)
281281
if err != nil {
282-
s.logger.Error("failed to build S3 table function",
282+
s.logger.Error("failed to build staging table function",
283283
slog.String("avroFilePath", avroFile.FilePath),
284284
slog.Any("error", err),
285285
slog.Uint64("part", i),
286286
slog.Uint64("numParts", numParts),
287287
slog.Int("chunkIdx", chunkIdx),
288288
)
289-
return fmt.Errorf("failed to build S3 table function: %w", err)
289+
return fmt.Errorf("failed to build staging table function: %w", err)
290290
}
291291

292292
var query string
293293
if numParts > 1 {
294294
query, err = buildInsertFromTableFunctionQueryWithPartitioning(
295-
ctx, insertConfig, s3TableFunction, i, numParts, chSettings)
295+
ctx, insertConfig, stagingTableFunction, i, numParts, chSettings)
296296
} else {
297-
query, err = buildInsertFromTableFunctionQuery(ctx, insertConfig, s3TableFunction, chSettings)
297+
query, err = buildInsertFromTableFunctionQuery(ctx, insertConfig, stagingTableFunction, chSettings)
298298
}
299299
if err != nil {
300300
s.logger.Error("failed to build insert query",
@@ -371,25 +371,30 @@ func (s *ClickHouseAvroSyncMethod) writeToAvroFile(
371371
return utils.AvroFile{}, err
372372
}
373373

374-
var s3AvroFileKey string
374+
var stagingAvroFileKey string
375375
if s3UuidPrefix {
376-
s3AvroFileKey = fmt.Sprintf("%s/%s/%s/%s.avro", prefix, uuid.NewString(), flowJobName, identifierForFile)
376+
stagingAvroFileKey = fmt.Sprintf("%s/%s/%s/%s.avro", prefix, uuid.NewString(), flowJobName, identifierForFile)
377377
} else {
378-
s3AvroFileKey = fmt.Sprintf("%s/%s/%s.avro", prefix, flowJobName, identifierForFile)
378+
stagingAvroFileKey = fmt.Sprintf("%s/%s/%s.avro", prefix, flowJobName, identifierForFile)
379379
}
380-
s3AvroFileKey = strings.TrimLeft(s3AvroFileKey, "/")
380+
stagingAvroFileKey = strings.TrimLeft(stagingAvroFileKey, "/")
381381

382382
r, w := io.Pipe()
383383
defer r.Close()
384384

385385
var writeOcfError error
386386
var numRows int64
387387
go func() {
388-
defer w.Close()
388+
defer func() {
389+
if r := recover(); r != nil {
390+
writeOcfError = fmt.Errorf("panic occurred during WriteOCF: %v", r)
391+
}
392+
w.Close()
393+
}()
389394
numRows, writeOcfError = ocfWriter.WriteOCF(ctx, env, w, typeConversions, numericTruncator)
390395
}()
391396

392-
if err := s.staging.Upload(ctx, env, s3AvroFileKey, r); err != nil {
397+
if err := s.staging.Upload(ctx, env, stagingAvroFileKey, r); err != nil {
393398
return utils.AvroFile{}, fmt.Errorf("failed to upload to staging: %w", err)
394399
}
395400
if writeOcfError != nil {
@@ -398,7 +403,7 @@ func (s *ClickHouseAvroSyncMethod) writeToAvroFile(
398403

399404
return utils.AvroFile{
400405
StorageLocation: utils.AvroS3Storage,
401-
FilePath: s3AvroFileKey,
406+
FilePath: stagingAvroFileKey,
402407
NumRecords: numRows,
403408
}, nil
404409
}

flow/connectors/clickhouse/staging.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,17 @@ func createStagingStore(
2727
return nil, fmt.Errorf("failed to get staging provider: %w", err)
2828
}
2929

30+
// Prefer unified PEERDB_CLICKHOUSE_STAGING_BUCKET_NAME, fall back to legacy S3-specific env var.
3031
bucketName, err := internal.PeerDBClickHouseStagingBucketName(ctx, env)
3132
if err != nil {
3233
return nil, fmt.Errorf("failed to get staging bucket name: %w", err)
3334
}
35+
if bucketName == "" {
36+
bucketName, err = internal.PeerDBClickHouseAWSS3BucketName(ctx, env)
37+
if err != nil {
38+
return nil, fmt.Errorf("failed to get S3 bucket name: %w", err)
39+
}
40+
}
3441

3542
switch strings.ToLower(provider) {
3643
case "s3", "":

flow/connectors/clickhouse/staging_gcs.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"time"
1010

1111
"cloud.google.com/go/storage"
12+
"github.com/google/uuid"
1213
"google.golang.org/api/iterator"
1314

1415
"github.com/PeerDB-io/peerdb/flow/internal"
@@ -108,7 +109,7 @@ func (g *gcsStagingStore) DeletePrefix(ctx context.Context, prefix string) error
108109
}
109110

110111
func (g *gcsStagingStore) Validate(ctx context.Context) error {
111-
testKey := g.prefix + "/_peerdb_check_" + time.Now().Format("20060102150405")
112+
testKey := strings.TrimPrefix(g.prefix+"/_peerdb_check_"+uuid.NewString(), "/")
112113
obj := g.client.Bucket(g.bucket).Object(testKey)
113114

114115
w := obj.NewWriter(ctx)

flow/internal/dynamicconf.go

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -726,18 +726,11 @@ func PeerDBClickHouseStagingProvider(ctx context.Context, env map[string]string)
726726
return dynLookup(ctx, env, "PEERDB_CLICKHOUSE_STAGING_PROVIDER")
727727
}
728728

729-
// PeerDBClickHouseStagingBucketName returns the staging bucket name, preferring
730-
// PEERDB_CLICKHOUSE_STAGING_BUCKET_NAME and falling back to the legacy
731-
// PEERDB_CLICKHOUSE_AWS_S3_BUCKET_NAME if empty.
732729
func PeerDBClickHouseStagingBucketName(ctx context.Context, env map[string]string) (string, error) {
733-
name, err := dynLookup(ctx, env, "PEERDB_CLICKHOUSE_STAGING_BUCKET_NAME")
734-
if err != nil {
735-
return "", err
736-
}
737-
if name != "" {
738-
return name, nil
739-
}
740-
// Fall back to legacy S3-specific env var.
730+
return dynLookup(ctx, env, "PEERDB_CLICKHOUSE_STAGING_BUCKET_NAME")
731+
}
732+
733+
func PeerDBClickHouseAWSS3BucketName(ctx context.Context, env map[string]string) (string, error) {
741734
return dynLookup(ctx, env, "PEERDB_CLICKHOUSE_AWS_S3_BUCKET_NAME")
742735
}
743736

0 commit comments

Comments
 (0)