@@ -4,11 +4,25 @@ const fs = require('fs');
44const path = require ( 'path' ) ;
55
66const TEST_SMILES = [
7- 'C(C1=CC=CC=C1)[Ti](CC1=CC=CC=C1)(CC1=CC=CC=C1)CC1=CC=CC=C1' ,
8- 'O=C(O)C[C@H](CC(C)C)CN' ,
9- 'CNCCC(C1=CC=CC=C1)OC2=CC=C(C=C2)C(F)(F)F' ,
7+ 'CCCCCCCCC=O' ,
108] ;
119
10+ const sleep = ( ms ) => new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
11+
12+ function getSpoofedHeaders ( targetUrl ) {
13+ try {
14+ const urlObj = new URL ( targetUrl ) ;
15+ return {
16+ 'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' ,
17+ 'Origin' : urlObj . origin ,
18+ 'Referer' : urlObj . origin + '/' ,
19+ 'Content-Type' : 'application/json'
20+ } ;
21+ } catch ( e ) {
22+ return { 'Content-Type' : 'application/json' } ;
23+ }
24+ }
25+
1226function loadWebservicesConfig ( ) {
1327 try {
1428 const webservicesPath = path . join ( process . cwd ( ) , 'public/marvin/js/webservices.js' ) ;
@@ -40,13 +54,20 @@ function loadWebservicesConfig() {
4054async function testServiceEndpoint ( url , timeout = 10000 ) {
4155 try {
4256 console . log ( `Testing endpoint: ${ url } ` ) ;
57+
58+ const headers = getSpoofedHeaders ( url ) ;
59+ delete headers [ 'Content-Type' ] ;
60+
4361 const response = await axios . get ( url , {
4462 timeout,
63+ headers : headers ,
4564 validateStatus : function ( status ) {
4665 return status < 500 ;
4766 }
4867 } ) ;
4968
69+ await sleep ( 500 ) ;
70+
5071 console . log ( `Endpoint ${ url } responded with status: ${ response . status } ` ) ;
5172 return {
5273 success : response . status < 400 || response . status === 405 ,
@@ -66,39 +87,48 @@ async function testServiceEndpoint(url, timeout = 10000) {
6687async function testSmilesConversion ( serviceUrl , smiles , timeout = 15000 ) {
6788 try {
6889 console . log ( `Testing SMILES conversion: ${ smiles } ` ) ;
69-
70- const formats = [ 'mol' , 'sdf' , ' smiles'] ;
90+
91+ const formats = [ 'mol' , 'smiles' ] ;
7192 const results = [ ] ;
7293
7394 for ( const format of formats ) {
74- try {
75- const response = await axios . post ( serviceUrl , {
76- structure : smiles ,
77- parameters : `${ format } `
78- } , {
79- timeout,
80- headers : {
81- 'Content-Type' : 'application/json'
95+ let retries = 1 ;
96+ let success = false ;
97+ let response = null ;
98+ let lastError = null ;
99+
100+ while ( retries >= 0 && ! success ) {
101+ try {
102+ await sleep ( 1000 ) ;
103+
104+ response = await axios . post ( serviceUrl , {
105+ structure : smiles ,
106+ parameters : `${ format } `
107+ } , {
108+ timeout,
109+ headers : getSpoofedHeaders ( serviceUrl )
110+ } ) ;
111+
112+ if ( response . status === 200 ) {
113+ success = true ;
82114 }
83- } ) ;
84-
85- const success = response . status === 200 && response . data ;
86- results . push ( {
87- format,
88- success,
89- status : response . status ,
90- hasData : ! ! response . data
91- } ) ;
92-
93- console . log ( `SMILES ${ smiles } -> ${ format } : ${ success ? 'SUCCESS' : 'FAILED' } ` ) ;
94- } catch ( error ) {
95- results . push ( {
96- format,
97- success : false ,
98- error : error . message
99- } ) ;
100- console . log ( `SMILES ${ smiles } -> ${ format } : FAILED (${ error . message } )` ) ;
115+ } catch ( error ) {
116+ lastError = error ;
117+ if ( error . response && error . response . status === 429 ) {
118+ console . log ( `Rate limited (429), waiting 3s...` ) ;
119+ await sleep ( 3000 ) ;
120+ }
121+ retries -- ;
122+ }
101123 }
124+
125+ results . push ( {
126+ format,
127+ success,
128+ status : response ? response . status : 'ERR' ,
129+ error : success ? null : ( lastError ? lastError . message : 'Unknown' )
130+ } ) ;
131+ console . log ( `SMILES ${ smiles } -> ${ format } : ${ success ? 'SUCCESS' : 'FAILED' } ` ) ;
102132 }
103133
104134 return {
@@ -107,12 +137,7 @@ async function testSmilesConversion(serviceUrl, smiles, timeout = 15000) {
107137 overallSuccess : results . some ( r => r . success )
108138 } ;
109139 } catch ( error ) {
110- console . error ( `SMILES conversion test failed for ${ smiles } :` , error . message ) ;
111- return {
112- smiles,
113- success : false ,
114- error : error . message
115- } ;
140+ return { smiles, success : false , error : error . message } ;
116141 }
117142}
118143
@@ -129,43 +154,18 @@ async function sendEmailNotification(failedServices, failedConversions) {
129154 try {
130155 const transporter = nodemailer . createTransporter ( {
131156 service : 'gmail' ,
132- auth : {
133- user : emailUser ,
134- pass : emailPass
135- }
157+ auth : { user : emailUser , pass : emailPass }
136158 } ) ;
137159
138- const failedServicesList = failedServices . map ( s => `- ${ s . url } : ${ s . error || s . status } ` ) . join ( '\n' ) ;
139- const failedConversionsList = failedConversions . map ( c => `- ${ c . smiles } : ${ c . error || 'Conversion failed ' } ` ) . join ( '\n' ) ;
160+ const failedList = [ ... failedServices , ... failedConversions ]
161+ . map ( f => `- ${ f . url || f . smiles } : ${ f . error || 'Failed ' } ` ) . join ( '\n' ) ;
140162
141- const mailOptions = {
163+ await transporter . sendMail ( {
142164 from : emailUser ,
143165 to : notificationEmail ,
144- subject : '🚨 Webservice Health Check Failed - SMILES Conversion Issues' ,
145- html : `
146- <h2>Webservice Health Check Failed</h2>
147- <p><strong>Time:</strong> ${ new Date ( ) . toISOString ( ) } </p>
148- <p><strong>Repository:</strong> StructuredSearch</p>
149-
150- <h3>Failed Services (${ failedServices . length } )</h3>
151- <pre>${ failedServicesList } </pre>
152-
153- <h3>Failed SMILES Conversions (${ failedConversions . length } )</h3>
154- <pre>${ failedConversionsList } </pre>
155-
156- <h3>Recommended Actions</h3>
157- <ul>
158- <li>Check the webservice server status</li>
159- <li>Verify network connectivity</li>
160- <li>Update webservice URLs if necessary</li>
161- <li>Check GitHub Issues for automated issue creation</li>
162- </ul>
163-
164- <p><em>This notification was sent automatically by the GitHub Actions workflow.</em></p>
165- `
166- } ;
167-
168- await transporter . sendMail ( mailOptions ) ;
166+ subject : '🚨 Webservice Health Check Failed' ,
167+ html : `<h3>Health Check Failed</h3><pre>${ failedList } </pre>`
168+ } ) ;
169169 console . log ( 'Email notification sent successfully' ) ;
170170 } catch ( error ) {
171171 console . error ( 'Failed to send email notification:' , error . message ) ;
@@ -193,37 +193,29 @@ async function runHealthCheck() {
193193
194194 console . log ( '\n=== Testing SMILES Conversions ===' ) ;
195195 const molconvertUrl = config . services . molconvert ;
196-
197- for ( const smiles of TEST_SMILES ) {
198- const result = await testSmilesConversion ( molconvertUrl , smiles ) ;
199- if ( ! result . overallSuccess ) {
200- hasFailures = true ;
201- failedConversions . push ( result ) ;
196+
197+ if ( ! hasFailures ) {
198+ for ( const smiles of TEST_SMILES ) {
199+ const result = await testSmilesConversion ( molconvertUrl , smiles ) ;
200+ if ( ! result . overallSuccess ) {
201+ hasFailures = true ;
202+ failedConversions . push ( result ) ;
203+ }
202204 }
203205 }
204-
205- console . log ( '\n=== Health Check Summary ===' ) ;
206- console . log ( `Failed Services: ${ failedServices . length } ` ) ;
207- console . log ( `Failed Conversions: ${ failedConversions . length } ` ) ;
208- console . log ( `Overall Status: ${ hasFailures ? 'FAILED' : 'PASSED' } ` ) ;
206+
207+ console . log ( '\n=== Summary ===' ) ;
208+ console . log ( `Status: ${ hasFailures ? 'FAILED' : 'PASSED' } ` ) ;
209209
210210 if ( hasFailures ) {
211211 await sendEmailNotification ( failedServices , failedConversions ) ;
212- }
213-
214- const hasConversionFailures = failedConversions . length > 0 ;
215-
216- if ( hasConversionFailures ) {
217- console . error ( 'Health check failed - SMILES conversion is not working correctly' ) ;
218212 process . exit ( 1 ) ;
219213 } else {
220- console . log ( 'Health check passed - SMILES conversion is working correctly' ) ;
221214 process . exit ( 0 ) ;
222215 }
223216
224217 } catch ( error ) {
225- console . error ( 'Health check encountered an error:' , error . message ) ;
226- console . error ( error . stack ) ;
218+ console . error ( 'Error:' , error . message ) ;
227219 process . exit ( 1 ) ;
228220 }
229221}
@@ -232,9 +224,4 @@ if (require.main === module) {
232224 runHealthCheck ( ) ;
233225}
234226
235- module . exports = {
236- runHealthCheck,
237- testServiceEndpoint,
238- testSmilesConversion,
239- loadWebservicesConfig
240- } ;
227+ module . exports = { runHealthCheck } ;
0 commit comments