| 36337 |
amit |
1 |
package com.spice.profitmandi.service.cron;
|
|
|
2 |
|
|
|
3 |
import com.spice.profitmandi.dao.entity.transaction.CronBatch;
|
|
|
4 |
import com.spice.profitmandi.dao.entity.transaction.CronBatchItem;
|
|
|
5 |
import com.spice.profitmandi.dao.enumuration.transaction.CronBatchItemStatus;
|
|
|
6 |
import com.spice.profitmandi.dao.enumuration.transaction.CronBatchStatus;
|
|
|
7 |
import com.spice.profitmandi.dao.repository.transaction.CronBatchItemRepository;
|
|
|
8 |
import com.spice.profitmandi.dao.repository.transaction.CronBatchRepository;
|
|
|
9 |
import com.spice.profitmandi.service.mail.MailOutboxService;
|
|
|
10 |
import org.apache.logging.log4j.LogManager;
|
|
|
11 |
import org.apache.logging.log4j.Logger;
|
|
|
12 |
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
13 |
import org.springframework.stereotype.Service;
|
|
|
14 |
import org.springframework.transaction.annotation.Propagation;
|
|
|
15 |
import org.springframework.transaction.annotation.Transactional;
|
|
|
16 |
|
|
|
17 |
import java.time.LocalDateTime;
|
|
|
18 |
import java.time.format.DateTimeFormatter;
|
|
|
19 |
import java.util.List;
|
|
|
20 |
import java.util.Map;
|
|
|
21 |
|
|
|
22 |
@Service
|
|
|
23 |
public class CronBatchService {
|
|
|
24 |
|
|
|
25 |
private static final Logger LOGGER = LogManager.getLogger(CronBatchService.class);
|
|
|
26 |
private static final String[] TECHNOLOGY_EMAIL = {"amit.gupta@smartdukaan.com"};
|
|
|
27 |
private static final DateTimeFormatter DTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
28 |
|
|
|
29 |
@Autowired
|
|
|
30 |
private CronBatchRepository cronBatchRepository;
|
|
|
31 |
|
|
|
32 |
@Autowired
|
|
|
33 |
private CronBatchItemRepository cronBatchItemRepository;
|
|
|
34 |
|
|
|
35 |
@Autowired
|
|
|
36 |
private MailOutboxService mailOutboxService;
|
|
|
37 |
|
| 36357 |
amit |
38 |
/**
|
|
|
39 |
* Read-only guard used by OfferBatchService before creating a new batch.
|
|
|
40 |
* Returns any RUNNING batch for this offer (sellin or activation job name),
|
|
|
41 |
* or null if none. Wrapped in a read-only tx so callers running outside an
|
|
|
42 |
* existing transaction (e.g. background worker thread) can query safely.
|
|
|
43 |
*/
|
|
|
44 |
@Transactional(readOnly = true)
|
|
|
45 |
public CronBatch findRunningForOffer(int offerId) {
|
|
|
46 |
List<CronBatch> running = cronBatchRepository.selectRunningForOffer(offerId);
|
|
|
47 |
return running.isEmpty() ? null : running.get(0);
|
|
|
48 |
}
|
|
|
49 |
|
| 36337 |
amit |
50 |
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
|
|
51 |
public CronBatch createBatch(String jobName, Map<Integer, String> fofoIdPartnerNameMap) {
|
|
|
52 |
CronBatch batch = new CronBatch(jobName);
|
|
|
53 |
batch.setTotalCount(fofoIdPartnerNameMap.size());
|
|
|
54 |
cronBatchRepository.persist(batch);
|
|
|
55 |
|
|
|
56 |
for (Map.Entry<Integer, String> entry : fofoIdPartnerNameMap.entrySet()) {
|
|
|
57 |
CronBatchItem item = new CronBatchItem(batch.getId(), entry.getKey(), entry.getValue());
|
|
|
58 |
cronBatchItemRepository.persist(item);
|
|
|
59 |
}
|
|
|
60 |
|
|
|
61 |
LOGGER.info("Created batch {} for job {} with {} items", batch.getId(), jobName, fofoIdPartnerNameMap.size());
|
|
|
62 |
return batch;
|
|
|
63 |
}
|
|
|
64 |
|
|
|
65 |
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
|
|
66 |
public void markItemSuccess(int batchId, int fofoId) {
|
|
|
67 |
List<CronBatchItem> items = cronBatchItemRepository.selectByBatchIdAndStatus(batchId, CronBatchItemStatus.PENDING);
|
|
|
68 |
for (CronBatchItem item : items) {
|
|
|
69 |
if (item.getFofoId() == fofoId) {
|
|
|
70 |
item.markSuccess();
|
|
|
71 |
break;
|
|
|
72 |
}
|
|
|
73 |
}
|
|
|
74 |
}
|
|
|
75 |
|
|
|
76 |
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
|
|
77 |
public void markItemFailed(int batchId, int fofoId, String errorMessage) {
|
|
|
78 |
List<CronBatchItem> items = cronBatchItemRepository.selectByBatchIdAndStatus(batchId, CronBatchItemStatus.PENDING);
|
|
|
79 |
for (CronBatchItem item : items) {
|
|
|
80 |
if (item.getFofoId() == fofoId) {
|
|
|
81 |
item.markFailed(errorMessage);
|
|
|
82 |
break;
|
|
|
83 |
}
|
|
|
84 |
}
|
|
|
85 |
}
|
|
|
86 |
|
|
|
87 |
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
|
|
88 |
public void finalizeBatch(int batchId) {
|
|
|
89 |
CronBatch batch = cronBatchRepository.selectById(batchId);
|
|
|
90 |
List<CronBatchItem> failedItems = cronBatchItemRepository.selectFailedByBatchId(batchId);
|
|
|
91 |
|
|
|
92 |
int failureCount = failedItems.size();
|
|
|
93 |
int successCount = batch.getTotalCount() - failureCount;
|
|
|
94 |
|
|
|
95 |
batch.setSuccessCount(successCount);
|
|
|
96 |
batch.setFailureCount(failureCount);
|
|
|
97 |
batch.setCompletedAt(LocalDateTime.now());
|
|
|
98 |
batch.setStatus(failureCount == 0 ? CronBatchStatus.COMPLETED : CronBatchStatus.PARTIAL_FAILURE);
|
|
|
99 |
|
|
|
100 |
LOGGER.info("Batch {} finalized: {} success, {} failed", batchId, successCount, failureCount);
|
|
|
101 |
|
|
|
102 |
if (failureCount > 0) {
|
|
|
103 |
sendFailureEmail(batch, failedItems);
|
|
|
104 |
}
|
|
|
105 |
}
|
|
|
106 |
|
|
|
107 |
private void sendFailureEmail(CronBatch batch, List<CronBatchItem> failedItems) {
|
|
|
108 |
StringBuilder body = new StringBuilder();
|
|
|
109 |
body.append("Cron job: ").append(batch.getJobName()).append("\n");
|
|
|
110 |
body.append("Run time: ").append(batch.getStartedAt().format(DTF)).append("\n");
|
|
|
111 |
body.append("Total processed: ").append(batch.getTotalCount()).append("\n");
|
|
|
112 |
body.append("Success: ").append(batch.getSuccessCount()).append("\n");
|
|
|
113 |
body.append("Failures: ").append(batch.getFailureCount()).append("\n\n");
|
|
|
114 |
body.append("Partner failures:\n");
|
|
|
115 |
|
|
|
116 |
for (CronBatchItem item : failedItems) {
|
|
|
117 |
body.append("- ").append(item.getPartnerName())
|
|
|
118 |
.append(" (fofoId: ").append(item.getFofoId()).append(")")
|
|
|
119 |
.append(" — ").append(item.getErrorMessage())
|
|
|
120 |
.append("\n");
|
|
|
121 |
}
|
|
|
122 |
|
|
|
123 |
String subject = String.format("[CRON ALERT] %s — %d of %d partners failed",
|
|
|
124 |
batch.getJobName(), batch.getFailureCount(), batch.getTotalCount());
|
|
|
125 |
|
|
|
126 |
try {
|
|
|
127 |
mailOutboxService.queueMailViaGoogle(TECHNOLOGY_EMAIL, null, subject, body.toString(),
|
|
|
128 |
"CronBatchService." + batch.getJobName());
|
|
|
129 |
} catch (Exception e) {
|
|
|
130 |
LOGGER.error("Failed to send batch failure email for batch {}: {}", batch.getId(), e.getMessage());
|
|
|
131 |
}
|
|
|
132 |
}
|
|
|
133 |
}
|