Skip to content

Commit cfc0161

Browse files
authored
Merge pull request #2481 from keboola/petr-hosek-restart_disabled
Fix handling of restart disabled state
2 parents 8170cf4 + e3c806b commit cfc0161

3 files changed

Lines changed: 68 additions & 2 deletions

File tree

internal/pkg/service/appsproxy/proxy/apphandler/upstream/upstream.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,8 @@ func (u *AppUpstream) trace() chain.Middleware {
197197
DNSDone: func(info httptrace.DNSDoneInfo) {
198198
if info.Err != nil {
199199
u.wakeup(ctx, info.Err)
200+
} else {
201+
u.restartDisabled.Store(false)
200202
}
201203
},
202204
})

internal/pkg/service/appsproxy/proxy/pagewriter/restart_disabled.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ type RestartDisabledPageData struct {
1313
func (pw *Writer) WriteRestartDisabledPage(w http.ResponseWriter, req *http.Request, app api.AppConfig) {
1414
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate;")
1515
w.Header().Set("pragma", "no-cache")
16-
pw.writePage(w, req, "restart_disabled.gohtml", http.StatusNotFound, RestartDisabledPageData{
16+
pw.writePage(w, req, "restart_disabled.gohtml", http.StatusServiceUnavailable, RestartDisabledPageData{
1717
App: NewAppData(&app),
1818
})
1919
}

internal/pkg/service/appsproxy/proxy/proxy_test.go

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1842,7 +1842,7 @@ func TestAppProxyRouter(t *testing.T) {
18421842
require.NoError(t, err)
18431843
response, err := client.Do(request)
18441844
require.NoError(t, err)
1845-
if response.StatusCode == http.StatusNotFound {
1845+
if response.StatusCode == http.StatusServiceUnavailable {
18461846
body, err := io.ReadAll(response.Body)
18471847
require.NoError(t, err)
18481848
return strings.Contains(string(body), "Application Disabled")
@@ -1855,6 +1855,70 @@ func TestAppProxyRouter(t *testing.T) {
18551855
expectedNotifications: map[string]int{},
18561856
expectedWakeUps: map[string]int{},
18571857
},
1858+
{
1859+
name: "restart-disabled-flag-reset-on-dns-success",
1860+
run: func(t *testing.T, client *http.Client, m []*mockoidc.MockOIDC, appServer *testutil.AppServer, service *testutil.DataAppsAPI, dnsServer *dnsmock.Server) {
1861+
// Phase 1: Set restart disabled state
1862+
dnsServer.RemoveARecords(dns.Fqdn("app.local"))
1863+
1864+
service.WakeUpOverrides["123"] = func(w http.ResponseWriter, req *http.Request) {
1865+
w.Header().Set("Content-Type", "application/json")
1866+
w.WriteHeader(http.StatusBadRequest)
1867+
_, _ = fmt.Fprintln(w, `{
1868+
"code": 0,
1869+
"context": {
1870+
"code": "apps.restartDisabled"
1871+
},
1872+
"error": "App restart is disabled. Contact app maintainer.",
1873+
"exceptionId": "exception-208db995c92ed365d47bcc701ae4d802",
1874+
"status": "error"
1875+
}`)
1876+
}
1877+
1878+
// Request to public app - fails because the app doesn't have a DNS record
1879+
request, err := http.NewRequestWithContext(t.Context(), http.MethodGet, "https://public-123.hub.keboola.local/", nil)
1880+
require.NoError(t, err)
1881+
response, err := client.Do(request)
1882+
require.NoError(t, err)
1883+
// First request returns 503 Service Unavailable (Spinner) because wakeup is async
1884+
require.Equal(t, http.StatusServiceUnavailable, response.StatusCode)
1885+
1886+
// Wait for async wakeup to complete and flag to be set
1887+
assert.Eventually(t, func() bool {
1888+
request, err := http.NewRequestWithContext(t.Context(), http.MethodGet, "https://public-123.hub.keboola.local/", nil)
1889+
require.NoError(t, err)
1890+
response, err := client.Do(request)
1891+
require.NoError(t, err)
1892+
body, err := io.ReadAll(response.Body)
1893+
require.NoError(t, err)
1894+
return response.StatusCode == http.StatusServiceUnavailable && strings.Contains(string(body), "Application Disabled")
1895+
}, 5*time.Second, 100*time.Millisecond)
1896+
1897+
// Phase 2: Simulate app becoming available (restart enabled)
1898+
// Add DNS record back and remove wakeup override
1899+
dnsServer.AddARecord(dns.Fqdn("app.local"), net.ParseIP("127.0.0.1"))
1900+
delete(service.WakeUpOverrides, "123")
1901+
1902+
// Request should now succeed - DNS resolution succeeds, flag gets reset
1903+
request, err = http.NewRequestWithContext(t.Context(), http.MethodGet, "https://public-123.hub.keboola.local/", nil)
1904+
require.NoError(t, err)
1905+
response, err = client.Do(request)
1906+
require.NoError(t, err)
1907+
require.Equal(t, http.StatusOK, response.StatusCode)
1908+
body, err := io.ReadAll(response.Body)
1909+
require.NoError(t, err)
1910+
assert.Contains(t, string(body), "Hello, client")
1911+
1912+
// Verify flag stays reset - subsequent requests should continue to work
1913+
request, err = http.NewRequestWithContext(t.Context(), http.MethodGet, "https://public-123.hub.keboola.local/", nil)
1914+
require.NoError(t, err)
1915+
response, err = client.Do(request)
1916+
require.NoError(t, err)
1917+
require.Equal(t, http.StatusOK, response.StatusCode)
1918+
},
1919+
expectedNotifications: map[string]int{"123": 1},
1920+
expectedWakeUps: map[string]int{},
1921+
},
18581922
{
18591923
name: "private-one-provider-selector",
18601924
run: func(t *testing.T, client *http.Client, m []*mockoidc.MockOIDC, appServer *testutil.AppServer, service *testutil.DataAppsAPI, dnsServer *dnsmock.Server) {

0 commit comments

Comments
 (0)