bulltrackers-module 1.0.604 → 1.0.606
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,158 @@ 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
|
+
// First, check if computation results exist (computation may have completed but status wasn't updated)
|
|
1850
|
+
// This is especially important for "computing" status
|
|
1851
|
+
if (currentStatus === 'computing' || currentStatus === 'indexing') {
|
|
1852
|
+
try {
|
|
1853
|
+
const today = new Date().toISOString().split('T')[0];
|
|
1854
|
+
const userType = data.userType || 'SIGNED_IN_USER';
|
|
1855
|
+
|
|
1856
|
+
// Determine which computation to check based on user type
|
|
1857
|
+
let computationNames = [];
|
|
1858
|
+
if (userType === 'POPULAR_INVESTOR') {
|
|
1859
|
+
computationNames = ['PopularInvestorProfileMetrics'];
|
|
1860
|
+
// Check if also a signed-in user
|
|
1861
|
+
try {
|
|
1862
|
+
await isSignedInUser(db, targetId);
|
|
1863
|
+
computationNames.push('SignedInUserPIPersonalizedMetrics');
|
|
1864
|
+
} catch (e) {
|
|
1865
|
+
// Not a signed-in user
|
|
1866
|
+
}
|
|
1867
|
+
} else {
|
|
1868
|
+
computationNames = ['SignedInUserProfileMetrics'];
|
|
1869
|
+
// Check if also a PI
|
|
1870
|
+
try {
|
|
1871
|
+
await fetchPopularInvestorMasterList(db, String(targetId));
|
|
1872
|
+
computationNames.push('SignedInUserPIPersonalizedMetrics', 'PopularInvestorProfileMetrics');
|
|
1873
|
+
} catch (e) {
|
|
1874
|
+
// Not a PI
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
// Check if any computation results exist for today
|
|
1879
|
+
let computationFound = false;
|
|
1880
|
+
for (const compName of computationNames) {
|
|
1881
|
+
try {
|
|
1882
|
+
const pageRef = db.collection('unified_insights')
|
|
1883
|
+
.doc(today)
|
|
1884
|
+
.collection('results')
|
|
1885
|
+
.doc('popular-investor')
|
|
1886
|
+
.collection('computations')
|
|
1887
|
+
.doc(compName)
|
|
1888
|
+
.collection('pages')
|
|
1889
|
+
.doc(String(targetId));
|
|
1890
|
+
|
|
1891
|
+
const pageSnap = await pageRef.get();
|
|
1892
|
+
if (pageSnap.exists) {
|
|
1893
|
+
computationFound = true;
|
|
1894
|
+
break;
|
|
1895
|
+
}
|
|
1896
|
+
} catch (error) {
|
|
1897
|
+
// Continue checking other computations
|
|
1898
|
+
console.error(`Error checking computation ${compName} for ${today}:`, error);
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
// If computation results exist, mark as completed
|
|
1903
|
+
if (computationFound) {
|
|
1904
|
+
await doc.ref.update({
|
|
1905
|
+
status: 'completed',
|
|
1906
|
+
completedAt: new Date(),
|
|
1907
|
+
updatedAt: new Date()
|
|
1908
|
+
});
|
|
1909
|
+
|
|
1910
|
+
return {
|
|
1911
|
+
requestId: requestId,
|
|
1912
|
+
status: 'completed',
|
|
1913
|
+
type: data.userType,
|
|
1914
|
+
createdAt: data.createdAt ? (data.createdAt.toDate ? data.createdAt.toDate().toISOString() : (data.createdAt.toISOString ? data.createdAt.toISOString() : data.createdAt)) : null,
|
|
1915
|
+
updatedAt: new Date().toISOString(),
|
|
1916
|
+
completedAt: new Date().toISOString(),
|
|
1917
|
+
canRequest: true
|
|
1918
|
+
};
|
|
1919
|
+
}
|
|
1920
|
+
} catch (error) {
|
|
1921
|
+
// If error checking computation results, continue with timeout check
|
|
1922
|
+
console.error(`[getSyncStatus] Error checking computation results:`, error);
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
// Check age of request for timeout
|
|
1927
|
+
const createdAt = data.createdAt;
|
|
1928
|
+
const updatedAt = data.updatedAt;
|
|
1929
|
+
|
|
1930
|
+
// Use updatedAt if available, otherwise createdAt
|
|
1931
|
+
const checkTime = updatedAt || createdAt;
|
|
1932
|
+
if (checkTime) {
|
|
1933
|
+
const checkTimestamp = checkTime.toMillis ? checkTime.toMillis() : (checkTime.getTime ? checkTime.getTime() : new Date(checkTime).getTime());
|
|
1934
|
+
const age = Date.now() - checkTimestamp;
|
|
1935
|
+
|
|
1936
|
+
if (age > STALE_THRESHOLD_MS) {
|
|
1937
|
+
// Mark as failed due to timeout
|
|
1938
|
+
const errorMessage = `Sync request timed out after ${Math.round(age / 1000 / 60)} minutes. The task may have failed.`;
|
|
1939
|
+
await doc.ref.update({
|
|
1940
|
+
status: 'failed',
|
|
1941
|
+
error: errorMessage,
|
|
1942
|
+
failedAt: new Date(),
|
|
1943
|
+
updatedAt: new Date()
|
|
1944
|
+
});
|
|
1945
|
+
|
|
1946
|
+
return {
|
|
1947
|
+
requestId: requestId,
|
|
1948
|
+
status: 'failed',
|
|
1949
|
+
error: errorMessage,
|
|
1950
|
+
updatedAt: new Date(),
|
|
1951
|
+
type: data.userType,
|
|
1952
|
+
createdAt: createdAt,
|
|
1953
|
+
failedAt: new Date()
|
|
1954
|
+
};
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
|
|
1959
|
+
// Return current status with timestamps
|
|
1960
|
+
const result = {
|
|
1961
|
+
requestId: requestId,
|
|
1962
|
+
status: currentStatus,
|
|
1843
1963
|
type: data.userType
|
|
1844
1964
|
};
|
|
1965
|
+
|
|
1966
|
+
// Add timestamps if available
|
|
1967
|
+
if (data.createdAt) {
|
|
1968
|
+
result.createdAt = data.createdAt.toDate ? data.createdAt.toDate().toISOString() : (data.createdAt.toISOString ? data.createdAt.toISOString() : data.createdAt);
|
|
1969
|
+
}
|
|
1970
|
+
if (data.updatedAt) {
|
|
1971
|
+
result.updatedAt = data.updatedAt.toDate ? data.updatedAt.toDate().toISOString() : (data.updatedAt.toISOString ? data.updatedAt.toISOString() : data.updatedAt);
|
|
1972
|
+
}
|
|
1973
|
+
if (data.dispatchedAt) {
|
|
1974
|
+
result.dispatchedAt = data.dispatchedAt.toDate ? data.dispatchedAt.toDate().toISOString() : (data.dispatchedAt.toISOString ? data.dispatchedAt.toISOString() : data.dispatchedAt);
|
|
1975
|
+
}
|
|
1976
|
+
if (data.completedAt) {
|
|
1977
|
+
result.completedAt = data.completedAt.toDate ? data.completedAt.toDate().toISOString() : (data.completedAt.toISOString ? data.completedAt.toISOString() : data.completedAt);
|
|
1978
|
+
}
|
|
1979
|
+
if (data.failedAt) {
|
|
1980
|
+
result.failedAt = data.failedAt.toDate ? data.failedAt.toDate().toISOString() : (data.failedAt.toISOString ? data.failedAt.toISOString() : data.failedAt);
|
|
1981
|
+
}
|
|
1982
|
+
if (data.error) {
|
|
1983
|
+
result.error = data.error;
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
// Add canRequest flag (true if not in processing state or failed)
|
|
1987
|
+
result.canRequest = !isProcessingState && currentStatus !== 'failed';
|
|
1988
|
+
|
|
1989
|
+
return result;
|
|
1845
1990
|
};
|
|
1846
1991
|
|
|
1847
1992
|
// ==========================================
|