terminate a canceled session when its last connection is closed. (#520)

This commit is contained in:
Jim authored and GitHub committed 2020-10-02 10:01:46 -04:00
1 parent ecbff200e3
commit bd547fd0d6
3 files changed
+190 -5

No files matched your search

+92 -1
View File
@@ -4010,7 +4010,7 @@ begin;
after insert on session_connection
for each row execute procedure insert_new_connection_state();
-- update_connection_state_on_closed_reason() is used in an update insert trigger on the
-- update_connection_state_on_closed_reason() is used in an update trigger on the
-- session_connection table. it will insert a state of "closed" in
-- session_connection_state for the closed session connection.
create or replace function
@@ -4031,6 +4031,9 @@ begin;
values
(new.public_id, 'closed');
end if;
-- whenever we close a connection, we want to terminate the session if
-- possible.
perform terminate_session_if_possible(new.session_id);
end if;
return new;
end;
@@ -4116,6 +4119,94 @@ begin;
create trigger insert_session_connection_state before insert on session_connection_state
for each row execute procedure insert_session_connection_state();
-- terminate_session_if_possible takes a session id and terminates the session
-- if the following conditions are met:
-- * the session is expired and all its connections are closed.
-- * the session is canceling and all its connections are closed
-- * the session has exhausted its connection limit and all its connections
-- are closed.
--
-- Note: this function should align closely with the domain function
-- TerminateCompletedSessions
create or replace function
terminate_session_if_possible(terminate_session_id text)
returns void
as $$
begin
-- is terminate_session_id in a canceling state
with canceling_session(session_id) as
(
select
session_id
from
session_state ss
where
ss.session_id = terminate_session_id and
ss.state = 'canceling' and
ss.end_time is null
)
update session us
set termination_reason =
case
-- timed out sessions
when now() > us.expiration_time then 'timed out'
-- canceling sessions
when us.public_id in(
select
session_id
from
canceling_session cs
where
us.public_id = cs.session_id
) then 'canceled'
-- default: session connection limit reached.
else 'connection limit'
end
where
-- limit update to just the terminating_session_id
us.public_id = terminate_session_id and
termination_reason is null and
-- session expired or connection limit reached
(
-- expired sessions...
now() > us.expiration_time or
-- connection limit reached...
(
select count (*)
from session_connection sc
where
sc.session_id = us.public_id
) >= connection_limit or
-- canceled sessions
us.public_id in (
select
session_id
from
canceling_session cs
where
us.public_id = cs.session_id
)
) and
-- make sure there are no existing connections
us.public_id not in (
select
session_id
from
session_connection
where public_id in (
select
connection_id
from
session_connection_state
where
state != 'closed' and
end_time is null
)
);
end;
$$ language plpgsql;
commit;
`),
@@ -174,7 +174,7 @@ begin;
after insert on session_connection
for each row execute procedure insert_new_connection_state();
-- update_connection_state_on_closed_reason() is used in an update insert trigger on the
-- update_connection_state_on_closed_reason() is used in an update trigger on the
-- session_connection table. it will insert a state of "closed" in
-- session_connection_state for the closed session connection.
create or replace function
@@ -195,6 +195,9 @@ begin;
values
(new.public_id, 'closed');
end if;
-- whenever we close a connection, we want to terminate the session if
-- possible.
perform terminate_session_if_possible(new.session_id);
end if;
return new;
end;
@@ -280,4 +283,92 @@ begin;
create trigger insert_session_connection_state before insert on session_connection_state
for each row execute procedure insert_session_connection_state();
-- terminate_session_if_possible takes a session id and terminates the session
-- if the following conditions are met:
-- * the session is expired and all its connections are closed.
-- * the session is canceling and all its connections are closed
-- * the session has exhausted its connection limit and all its connections
-- are closed.
--
-- Note: this function should align closely with the domain function
-- TerminateCompletedSessions
create or replace function
terminate_session_if_possible(terminate_session_id text)
returns void
as $$
begin
-- is terminate_session_id in a canceling state
with canceling_session(session_id) as
(
select
session_id
from
session_state ss
where
ss.session_id = terminate_session_id and
ss.state = 'canceling' and
ss.end_time is null
)
update session us
set termination_reason =
case
-- timed out sessions
when now() > us.expiration_time then 'timed out'
-- canceling sessions
when us.public_id in(
select
session_id
from
canceling_session cs
where
us.public_id = cs.session_id
) then 'canceled'
-- default: session connection limit reached.
else 'connection limit'
end
where
-- limit update to just the terminating_session_id
us.public_id = terminate_session_id and
termination_reason is null and
-- session expired or connection limit reached
(
-- expired sessions...
now() > us.expiration_time or
-- connection limit reached...
(
select count (*)
from session_connection sc
where
sc.session_id = us.public_id
) >= connection_limit or
-- canceled sessions
us.public_id in (
select
session_id
from
canceling_session cs
where
us.public_id = cs.session_id
)
) and
-- make sure there are no existing connections
us.public_id not in (
select
session_id
from
session_connection
where public_id in (
select
connection_id
from
session_connection_state
where
state != 'closed' and
end_time is null
)
);
end;
$$ language plpgsql;
commit;
+6 -3
View File
@@ -892,13 +892,16 @@ func TestRepository_TerminateCompletedSessions(t *testing.T) {
return
}
assert.NoError(err)
assert.Equal(len(args.wantTermed), got)
t.Logf("terminated: %d", got)
var foundTerminated int
for _, ses := range args.sessions {
found, _, err := repo.LookupSession(context.Background(), ses.PublicId)
require.NoError(err)
_, shouldBeTerminated := args.wantTermed[found.PublicId]
if shouldBeTerminated {
if found.TerminationReason != "" {
foundTerminated += 1
}
assert.Equal(args.wantTermed[found.PublicId].String(), found.TerminationReason)
t.Logf("terminated %s has a connection limit of %d", found.PublicId, found.ConnectionLimit)
conn, err := repo.ListConnections(context.Background(), found.PublicId)
@@ -925,7 +928,7 @@ func TestRepository_TerminateCompletedSessions(t *testing.T) {
}
}
}
assert.Equal(len(args.wantTermed), foundTerminated)
})
}
}