bulltrackers-module 1.0.603 → 1.0.605
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1835,13 +1835,81 @@ const getSyncStatus = async (db, targetId) => {
|
|
|
1835
1835
|
|
|
1836
1836
|
if (snap.empty) return { status: 'never_requested' };
|
|
1837
1837
|
|
|
1838
|
-
const
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1838
|
+
const doc = snap.docs[0];
|
|
1839
|
+
const data = doc.data();
|
|
1840
|
+
const requestId = data.requestId;
|
|
1841
|
+
const currentStatus = data.status;
|
|
1842
|
+
|
|
1843
|
+
// Server-side timeout: Check if request is stale (older than 2 minutes and still processing)
|
|
1844
|
+
const STALE_THRESHOLD_MS = 2 * 60 * 1000; // 2 minutes
|
|
1845
|
+
const processingStates = ['queued', 'dispatched', 'processing', 'indexing', 'computing'];
|
|
1846
|
+
const isProcessingState = processingStates.includes(currentStatus);
|
|
1847
|
+
|
|
1848
|
+
if (isProcessingState) {
|
|
1849
|
+
// Check age of request
|
|
1850
|
+
const createdAt = data.createdAt;
|
|
1851
|
+
const updatedAt = data.updatedAt;
|
|
1852
|
+
|
|
1853
|
+
// Use updatedAt if available, otherwise createdAt
|
|
1854
|
+
const checkTime = updatedAt || createdAt;
|
|
1855
|
+
if (checkTime) {
|
|
1856
|
+
const checkTimestamp = checkTime.toMillis ? checkTime.toMillis() : (checkTime.getTime ? checkTime.getTime() : new Date(checkTime).getTime());
|
|
1857
|
+
const age = Date.now() - checkTimestamp;
|
|
1858
|
+
|
|
1859
|
+
if (age > STALE_THRESHOLD_MS) {
|
|
1860
|
+
// Mark as failed due to timeout
|
|
1861
|
+
const errorMessage = `Sync request timed out after ${Math.round(age / 1000 / 60)} minutes. The task may have failed.`;
|
|
1862
|
+
await doc.ref.update({
|
|
1863
|
+
status: 'failed',
|
|
1864
|
+
error: errorMessage,
|
|
1865
|
+
failedAt: new Date(),
|
|
1866
|
+
updatedAt: new Date()
|
|
1867
|
+
});
|
|
1868
|
+
|
|
1869
|
+
return {
|
|
1870
|
+
requestId: requestId,
|
|
1871
|
+
status: 'failed',
|
|
1872
|
+
error: errorMessage,
|
|
1873
|
+
updatedAt: new Date(),
|
|
1874
|
+
type: data.userType,
|
|
1875
|
+
createdAt: createdAt,
|
|
1876
|
+
failedAt: new Date()
|
|
1877
|
+
};
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
// Return current status with timestamps
|
|
1883
|
+
const result = {
|
|
1884
|
+
requestId: requestId,
|
|
1885
|
+
status: currentStatus,
|
|
1843
1886
|
type: data.userType
|
|
1844
1887
|
};
|
|
1888
|
+
|
|
1889
|
+
// Add timestamps if available
|
|
1890
|
+
if (data.createdAt) {
|
|
1891
|
+
result.createdAt = data.createdAt.toDate ? data.createdAt.toDate().toISOString() : (data.createdAt.toISOString ? data.createdAt.toISOString() : data.createdAt);
|
|
1892
|
+
}
|
|
1893
|
+
if (data.updatedAt) {
|
|
1894
|
+
result.updatedAt = data.updatedAt.toDate ? data.updatedAt.toDate().toISOString() : (data.updatedAt.toISOString ? data.updatedAt.toISOString() : data.updatedAt);
|
|
1895
|
+
}
|
|
1896
|
+
if (data.dispatchedAt) {
|
|
1897
|
+
result.dispatchedAt = data.dispatchedAt.toDate ? data.dispatchedAt.toDate().toISOString() : (data.dispatchedAt.toISOString ? data.dispatchedAt.toISOString() : data.dispatchedAt);
|
|
1898
|
+
}
|
|
1899
|
+
if (data.completedAt) {
|
|
1900
|
+
result.completedAt = data.completedAt.toDate ? data.completedAt.toDate().toISOString() : (data.completedAt.toISOString ? data.completedAt.toISOString() : data.completedAt);
|
|
1901
|
+
}
|
|
1902
|
+
if (data.failedAt) {
|
|
1903
|
+
result.failedAt = data.failedAt.toDate ? data.failedAt.toDate().toISOString() : (data.failedAt.toISOString ? data.failedAt.toISOString() : data.failedAt);
|
|
1904
|
+
}
|
|
1905
|
+
if (data.error) {
|
|
1906
|
+
result.error = data.error;
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
// Add canRequest flag (true if not in processing state or failed)
|
|
1910
|
+
result.canRequest = !isProcessingState && currentStatus !== 'failed';
|
|
1911
|
+
|
|
1912
|
+
return result;
|
|
1845
1913
|
};
|
|
1846
1914
|
|
|
1847
1915
|
// ==========================================
|
|
@@ -1935,39 +2003,51 @@ const checkDataStatus = async (db, userId) => {
|
|
|
1935
2003
|
let computationDate = null;
|
|
1936
2004
|
let fallbackWindowExhausted = false;
|
|
1937
2005
|
|
|
1938
|
-
// Determine which
|
|
1939
|
-
|
|
2006
|
+
// Determine which computations to check based on user type
|
|
2007
|
+
// Signed-in users always have SignedInUserProfileMetrics
|
|
2008
|
+
// If they're also a PI, they may have SignedInUserPIPersonalizedMetrics
|
|
2009
|
+
const computationNames = ['SignedInUserProfileMetrics'];
|
|
1940
2010
|
try {
|
|
1941
2011
|
await fetchPopularInvestorMasterList(db, userId);
|
|
1942
|
-
|
|
2012
|
+
// User is a PI, also check for PI-specific computation
|
|
2013
|
+
computationNames.push('SignedInUserPIPersonalizedMetrics');
|
|
1943
2014
|
} catch (e) {
|
|
1944
|
-
// User is not a PI,
|
|
2015
|
+
// User is not a PI, only check SignedInUserProfileMetrics
|
|
1945
2016
|
}
|
|
1946
2017
|
|
|
1947
2018
|
// Check for computation results in the last 7 days
|
|
2019
|
+
// Check all relevant computation names for this user
|
|
1948
2020
|
for (let i = 0; i < lookbackDays; i++) {
|
|
1949
2021
|
const checkDate = new Date(today);
|
|
1950
2022
|
checkDate.setDate(checkDate.getDate() - i);
|
|
1951
2023
|
const dateStr = checkDate.toISOString().split('T')[0];
|
|
1952
2024
|
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
.collection('
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
2025
|
+
// Check each computation name
|
|
2026
|
+
for (const compName of computationNames) {
|
|
2027
|
+
try {
|
|
2028
|
+
const pageRef = db.collection('unified_insights')
|
|
2029
|
+
.doc(dateStr)
|
|
2030
|
+
.collection('results')
|
|
2031
|
+
.doc('popular-investor')
|
|
2032
|
+
.collection('computations')
|
|
2033
|
+
.doc(compName)
|
|
2034
|
+
.collection('pages')
|
|
2035
|
+
.doc(String(userId));
|
|
2036
|
+
|
|
2037
|
+
const pageSnap = await pageRef.get();
|
|
2038
|
+
if (pageSnap.exists) {
|
|
2039
|
+
computationDate = dateStr;
|
|
2040
|
+
break;
|
|
2041
|
+
}
|
|
2042
|
+
} catch (error) {
|
|
2043
|
+
// Continue checking other dates/computations
|
|
2044
|
+
console.error(`Error checking computation ${compName} for ${dateStr}:`, error);
|
|
1967
2045
|
}
|
|
1968
|
-
}
|
|
1969
|
-
|
|
1970
|
-
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
// If we found a computation date, stop checking
|
|
2049
|
+
if (computationDate) {
|
|
2050
|
+
break;
|
|
1971
2051
|
}
|
|
1972
2052
|
}
|
|
1973
2053
|
|
|
@@ -244,7 +244,12 @@ async function handleComputationTask(message, config, dependencies) {
|
|
|
244
244
|
computation,
|
|
245
245
|
getComputationDisplayName(computation),
|
|
246
246
|
true,
|
|
247
|
-
null
|
|
247
|
+
null,
|
|
248
|
+
{
|
|
249
|
+
collectionRegistry: dependencies.collectionRegistry,
|
|
250
|
+
config: config,
|
|
251
|
+
notificationType: 'userActionCompletions'
|
|
252
|
+
}
|
|
248
253
|
);
|
|
249
254
|
} catch (notifError) {
|
|
250
255
|
// Non-critical, log and continue
|
|
@@ -291,7 +296,12 @@ async function handleComputationTask(message, config, dependencies) {
|
|
|
291
296
|
computation,
|
|
292
297
|
getComputationDisplayName(computation),
|
|
293
298
|
false,
|
|
294
|
-
err.message
|
|
299
|
+
err.message,
|
|
300
|
+
{
|
|
301
|
+
collectionRegistry: dependencies.collectionRegistry,
|
|
302
|
+
config: config,
|
|
303
|
+
notificationType: 'userActionCompletions'
|
|
304
|
+
}
|
|
295
305
|
);
|
|
296
306
|
} catch (notifError) {
|
|
297
307
|
// Non-critical, log and continue
|