Subversion Repositories SmartDukaan

Rev

Rev 37083 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
36306 amit 1
package com.smartdukaan.cron.scheduled;
2
 
3
import com.spice.profitmandi.dao.entity.transaction.CronBatch;
36338 amit 4
import com.spice.profitmandi.service.cron.CronBatchService;
36343 amit 5
import com.spice.profitmandi.service.offers.OfferBatchService;
37083 amit 6
import com.spice.profitmandi.service.pricing.PriceDropBatchService;
36306 amit 7
import com.spice.profitmandi.service.transaction.PartnerLimitUpdateData;
8
import org.apache.logging.log4j.LogManager;
9
import org.apache.logging.log4j.Logger;
10
import org.springframework.beans.factory.annotation.Autowired;
11
import org.springframework.stereotype.Component;
12
 
13
import java.util.LinkedHashMap;
14
import java.util.List;
15
 
16
/**
17
 * Batch-aware scheduled tasks with per-partner transaction isolation.
18
 * NO @Transactional at class level — each partner gets its own transaction
19
 * via REQUIRES_NEW in the helper beans.
20
 *
21
 * Tracks every run in cron_batch / cron_batch_item tables.
36343 amit 22
 * Sends failure summary email on partial failures.
36306 amit 23
 */
24
@Component
25
public class BatchScheduledTasks {
26
 
27
    private static final Logger LOGGER = LogManager.getLogger(BatchScheduledTasks.class);
28
 
29
    @Autowired
30
    private CronBatchService cronBatchService;
31
 
32
    @Autowired
36343 amit 33
    private OfferBatchService offerBatchService;
36306 amit 34
 
35
    @Autowired
36
    private PartnerLimitHelper partnerLimitHelper;
37
 
37083 amit 38
    @Autowired
39
    private PriceDropBatchService priceDropBatchService;
40
 
37589 amit 41
    @Autowired
42
    private com.spice.profitmandi.service.PartnerInvestmentSweepService partnerInvestmentSweepService;
43
 
36306 amit 44
    /**
37589 amit 45
     * Recomputes every active partner's investment snapshot, then recomputes the credit limit for
46
     * the partners whose base actually moved.
47
     *
48
     * <p>Runs every 2 minutes. Measured on production: ~3.5s of batched reads for ~980 partners,
49
     * with an average of 3 partners (peak 18) showing a changed base per window — so the limit work
50
     * that follows is a handful of rows, not a full scan.
51
     *
52
     * <p>Investment and utilisation are read in the same pass deliberately. Reading them at
53
     * different vintages is what let an advance payment be counted twice — once as a cached wallet
54
     * balance and once as the loan repayment it funded — and overstate a limit by the payment x the
55
     * partner's tier.
56
     */
57
    public void sweepPartnerInvestment() throws Exception {
58
        List<Integer> changedBases;
59
        try {
60
            changedBases = partnerInvestmentSweepService.sweep();
61
        } catch (Exception e) {
62
            LOGGER.error("Investment sweep failed: {}", e.getMessage(), e);
63
            return;
64
        }
65
        if (changedBases.isEmpty()) {
66
            return;
67
        }
68
        updatePartnerLimitWithBatch(changedBases);
69
    }
70
 
71
    /** Daily refresh of the time-driven aged-Apple and live-demo haircuts. */
72
    public void refreshAgedStockDaily() {
73
        try {
74
            partnerInvestmentSweepService.refreshAgedStockDaily();
75
        } catch (Exception e) {
76
            LOGGER.error("Aged stock daily refresh failed: {}", e.getMessage(), e);
77
        }
78
    }
79
 
80
    /**
36343 amit 81
     * CLI entrypoint for cron: delegates to shared OfferBatchService (also used by web/fofo controllers).
36306 amit 82
     */
83
    public void processOfferWithBatch(int offerId) throws Exception {
36343 amit 84
        offerBatchService.processOfferWithBatch(offerId);
36306 amit 85
    }
86
 
87
    /**
37083 amit 88
     * Scheduled entrypoint: delegates to shared PriceDropBatchService.
89
     * Reprocesses (rejects) price drops for IMEIs activated before the drop date,
90
     * each drop in its own REQUIRES_NEW transaction so user_wallet locks are held
91
     * per-drop instead of for the whole run.
92
     */
93
    public void reprocessPriceDropsWithBatch() {
94
        priceDropBatchService.reprocessPriceDropsWithBatch();
95
    }
96
 
97
    /**
36306 amit 98
     * Recalculates partner credit limits. Only writes to partners where values actually changed.
99
     *
100
     * Flow:
101
     * 1. Read phase: calculate limits for all 1,500 partners, compare with current values
102
     * 2. Create batch with only changed partners (~50-100 typically)
103
     * 3. Per-partner: update in REQUIRES_NEW transaction
104
     * 4. Finalize: counts + failure email
105
     */
106
    public void updatePartnerLimitWithBatch() throws Exception {
37589 amit 107
        updatePartnerLimitWithBatch(null);
108
    }
109
 
110
    /**
111
     * @param restrictTo when non-null, only recalculate these partners. Passed by the investment
112
     * sweep with the partners whose base moved.
113
     */
114
    public void updatePartnerLimitWithBatch(java.util.Collection<Integer> restrictTo) throws Exception {
36306 amit 115
        List<PartnerLimitUpdateData> changedPartners;
116
        try {
37589 amit 117
            changedPartners = partnerLimitHelper.calculateChangedPartnerLimits(restrictTo);
36306 amit 118
        } catch (Exception e) {
119
            LOGGER.error("Failed to calculate partner limits: {}", e.getMessage());
120
            return;
121
        }
122
 
123
        if (changedPartners.isEmpty()) {
124
            LOGGER.info("No partner limits changed, skipping");
125
            return;
126
        }
127
 
128
        LinkedHashMap<Integer, String> fofoIdPartnerNameMap = new LinkedHashMap<>();
129
        for (PartnerLimitUpdateData data : changedPartners) {
130
            fofoIdPartnerNameMap.put(data.getFofoId(), "fofo-" + data.getFofoId());
131
        }
132
 
133
        CronBatch batch = cronBatchService.createBatch("updatePartnerLimit", fofoIdPartnerNameMap);
134
 
135
        for (PartnerLimitUpdateData data : changedPartners) {
136
            try {
137
                partnerLimitHelper.updateSinglePartnerLimit(batch.getId(), data);
138
            } catch (Exception e) {
139
                LOGGER.error("updatePartnerLimit failed for fofoId={}: {}", data.getFofoId(), e.getMessage());
140
                cronBatchService.markItemFailed(batch.getId(), data.getFofoId(), e.getMessage());
141
            }
142
        }
143
 
144
        cronBatchService.finalizeBatch(batch.getId());
145
    }
146
}